Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ec8117e1c | ||
|
|
3c68a26794 | ||
|
|
fda89933d0 | ||
|
|
d8f721db3b | ||
|
|
28339ce7c1 | ||
|
|
edda3179dd | ||
|
|
1d79990656 | ||
|
|
2a47362195 | ||
|
|
02d5951f8b | ||
|
|
b126c62365 | ||
|
|
bbaf1779ea | ||
|
|
65ddd6f5d8 | ||
|
|
772bc18eb8 | ||
|
|
d503818169 | ||
|
|
b209e73386 | ||
|
|
6c381b0ecc | ||
|
|
e3f0fa6756 | ||
|
|
35cb273592 | ||
|
|
b76f410c34 | ||
|
|
d3678531b7 | ||
|
|
122ca599de | ||
|
|
96fcec788c | ||
|
|
1c67b39a3e | ||
|
|
30fea4a705 | ||
|
|
7c0763c78a | ||
|
|
b8c593b110 | ||
|
|
782af959a0 | ||
|
|
6df227d231 | ||
|
|
5b1432e4e8 | ||
|
|
7ca4e4ec74 | ||
|
|
655ef1eed6 | ||
|
|
04be60577a | ||
|
|
63d2ec7b02 | ||
|
|
06b6afd557 | ||
|
|
32f4d6af47 | ||
|
|
264b177b38 | ||
|
|
67a1c5460a | ||
|
|
a20b7821f2 | ||
|
|
069cc152ca | ||
|
|
7b57be669c | ||
|
|
2f051e9eed | ||
|
|
8d1d018fe1 | ||
|
|
3c5bc27750 | ||
|
|
6c047eca8e | ||
|
|
a31e753841 |
@@ -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)?
|
||||||
@@ -30,3 +30,6 @@
|
|||||||
[submodule "src/main/jni/mbedtls"]
|
[submodule "src/main/jni/mbedtls"]
|
||||||
path = src/main/jni/mbedtls
|
path = src/main/jni/mbedtls
|
||||||
url = https://github.com/ARMmbed/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
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ resolvers += Resolver.jcenterRepo
|
|||||||
useSupportVectors
|
useSupportVectors
|
||||||
|
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
"com.android.support" % "design" % "24.2.0",
|
"com.android.support" % "design" % "24.2.1",
|
||||||
"com.android.support" % "gridlayout-v7" % "24.2.0",
|
"com.android.support" % "gridlayout-v7" % "24.2.1",
|
||||||
"com.github.clans" % "fab" % "1.6.4",
|
"com.github.clans" % "fab" % "1.6.4",
|
||||||
"com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01",
|
"com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01",
|
||||||
"com.github.kevinsawicki" % "http-request" % "6.0",
|
"com.github.kevinsawicki" % "http-request" % "6.0",
|
||||||
@@ -41,7 +41,7 @@ libraryDependencies ++= Seq(
|
|||||||
"com.j256.ormlite" % "ormlite-android" % "5.0",
|
"com.j256.ormlite" % "ormlite-android" % "5.0",
|
||||||
"com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2",
|
"com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2",
|
||||||
"dnsjava" % "dnsjava" % "2.1.7",
|
"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",
|
"me.dm7.barcodescanner" % "zxing" % "1.9",
|
||||||
"net.glxn.qrgen" % "android" % "2.0"
|
"net.glxn.qrgen" % "android" % "2.0"
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
Submodule kcptun/go updated: 70f0438db8...c3f75e654d
+1
-1
Submodule kcptun/kcptun updated: 9afbc4985d...e44d8c9041
+2
-1
@@ -51,7 +51,8 @@ export PATH=$GOROOT/bin:$PATH
|
|||||||
pushd kcptun/client
|
pushd kcptun/client
|
||||||
|
|
||||||
echo "Get dependences for kcptun"
|
echo "Get dependences for kcptun"
|
||||||
go get -u github.com/madeye/kcp-go
|
go get -u github.com/xtaci/kcp-go
|
||||||
|
go get -u github.com/xtaci/smux
|
||||||
go get
|
go get
|
||||||
|
|
||||||
echo "Cross compile kcptun for arm"
|
echo "Cross compile kcptun for arm"
|
||||||
|
|||||||
+1
-1
@@ -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")
|
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.10")
|
||||||
|
|
||||||
|
|||||||
@@ -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="147"
|
android:versionCode="157"
|
||||||
android:versionName="3.0.5">
|
android:versionName="3.1.5">
|
||||||
|
|
||||||
<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"/>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.github.shadowsocks.aidl.IShadowsocksServiceCallback;
|
|||||||
|
|
||||||
interface IShadowsocksService {
|
interface IShadowsocksService {
|
||||||
int getState();
|
int getState();
|
||||||
|
String getProfileName();
|
||||||
|
|
||||||
oneway void registerCallback(IShadowsocksServiceCallback cb);
|
oneway void registerCallback(IShadowsocksServiceCallback cb);
|
||||||
oneway void unregisterCallback(IShadowsocksServiceCallback cb);
|
oneway void unregisterCallback(IShadowsocksServiceCallback cb);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.github.shadowsocks.aidl;
|
package com.github.shadowsocks.aidl;
|
||||||
|
|
||||||
interface IShadowsocksServiceCallback {
|
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);
|
oneway void trafficUpdated(long txRate, long rxRate, long txTotal, long rxTotal);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+53
-9
@@ -371,7 +371,9 @@ PDNSD_SOURCES := $(wildcard $(LOCAL_PATH)/pdnsd/src/*.c)
|
|||||||
LOCAL_MODULE := pdnsd
|
LOCAL_MODULE := pdnsd
|
||||||
LOCAL_SRC_FILES := $(PDNSD_SOURCES:$(LOCAL_PATH)/%=%)
|
LOCAL_SRC_FILES := $(PDNSD_SOURCES:$(LOCAL_PATH)/%=%)
|
||||||
LOCAL_CFLAGS := -DANDROID -Wall -O2 -I$(LOCAL_PATH)/pdnsd \
|
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)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
@@ -381,25 +383,29 @@ include $(BUILD_EXECUTABLE)
|
|||||||
|
|
||||||
include $(CLEAR_VARS)
|
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_MODULE := ss-local
|
||||||
LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES))
|
LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES))
|
||||||
LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DMODULE_LOCAL \
|
LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DMODULE_LOCAL \
|
||||||
-DUSE_CRYPTO_MBEDTLS -DANDROID -DHAVE_CONFIG_H \
|
-DUSE_CRYPTO_MBEDTLS -DANDROID -DHAVE_CONFIG_H \
|
||||||
-DCONNECT_IN_PROGRESS=EINPROGRESS \
|
-DCONNECT_IN_PROGRESS=EINPROGRESS \
|
||||||
|
-I$(LOCAL_PATH)/include/shadowsocks-libev \
|
||||||
-I$(LOCAL_PATH)/include \
|
-I$(LOCAL_PATH)/include \
|
||||||
-I$(LOCAL_PATH)/libancillary \
|
-I$(LOCAL_PATH)/libancillary \
|
||||||
-I$(LOCAL_PATH)/mbedtls/include \
|
-I$(LOCAL_PATH)/mbedtls/include \
|
||||||
|
-I$(LOCAL_PATH)/pcre \
|
||||||
-I$(LOCAL_PATH)/shadowsocks-libev/libudns \
|
-I$(LOCAL_PATH)/shadowsocks-libev/libudns \
|
||||||
-I$(LOCAL_PATH)/shadowsocks-libev/libcork/include \
|
-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 \
|
||||||
-I$(LOCAL_PATH)/shadowsocks-libev/libsodium/src/libsodium/include/sodium \
|
-I$(LOCAL_PATH)/shadowsocks-libev/libsodium/src/libsodium/include/sodium \
|
||||||
-I$(LOCAL_PATH)/shadowsocks-libev/libipset/include \
|
-I$(LOCAL_PATH)/shadowsocks-libev/libipset/include \
|
||||||
-I$(LOCAL_PATH)/shadowsocks-libev/libev \
|
-I$(LOCAL_PATH)/shadowsocks-libev/libev
|
||||||
-I$(LOCAL_PATH)/include/shadowsocks-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
|
LOCAL_LDLIBS := -llog
|
||||||
|
|
||||||
@@ -551,17 +557,55 @@ include $(BUILD_EXECUTABLE)
|
|||||||
|
|
||||||
include $(CLEAR_VARS)
|
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_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)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
# Import cpufeatures
|
# Import cpufeatures
|
||||||
$(call import-module,android/cpufeatures)
|
$(call import-module,android/cpufeatures)
|
||||||
|
|
||||||
|
|||||||
@@ -417,3 +417,9 @@
|
|||||||
|
|
||||||
/* Define as `fork' if `vfork' does not work. */
|
/* Define as `fork' if `vfork' does not work. */
|
||||||
/* #undef vfork */
|
/* #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 */
|
||||||
|
|||||||
Submodule
+1
Submodule src/main/jni/pcre added at 0ea9883633
+1
-1
Submodule src/main/jni/pdnsd updated: b51fd4f65c...698275907b
Submodule src/main/jni/shadowsocks-libev updated: d31210c217...2868e7e7b2
@@ -1,3 +1,4 @@
|
|||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
@@ -11,4 +12,4 @@
|
|||||||
<path
|
<path
|
||||||
android:fillColor="#fff"
|
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" />
|
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>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
@@ -11,4 +12,4 @@
|
|||||||
<path
|
<path
|
||||||
android:fillColor="#fff"
|
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" />
|
android:pathData="M 9.45 17.56 L 12.09 18.41 L 9.46 22 L 9.45 17.56 Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--suppress NewApi -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
@@ -22,4 +23,4 @@
|
|||||||
<path
|
<path
|
||||||
android:fillColor="#fff"
|
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" />
|
android:pathData="M8.56,8.56L0,12.8l6.83,2.57,4.64-3.9ZM6.44,13.08L5,12.55l5-2.47Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|||||||
@@ -46,6 +46,13 @@
|
|||||||
<string name="auto_set_gfwlist">CHN Маршрут</string>
|
<string name="auto_set_gfwlist">CHN Маршрут</string>
|
||||||
<string name="auto_set_gfwlist_summary">Игнорировать все сайты находящиеся в Китае</string>
|
<string name="auto_set_gfwlist_summary">Игнорировать все сайты находящиеся в Китае</string>
|
||||||
<string name="route_list">Маршрут</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">Прокси для выбранных приложений</string>
|
||||||
<string name="proxied_apps_summary">Установить прокси для выбранных приложений, требует режим NAT под Android 4.x</string>
|
<string name="proxied_apps_summary">Установить прокси для выбранных приложений, требует режим NAT под Android 4.x</string>
|
||||||
<string name="on">Вкл</string>
|
<string name="on">Вкл</string>
|
||||||
|
|||||||
@@ -110,6 +110,8 @@
|
|||||||
<item>绕过局域网地址</item>
|
<item>绕过局域网地址</item>
|
||||||
<item>绕过中国大陆地址</item>
|
<item>绕过中国大陆地址</item>
|
||||||
<item>绕过局域网及中国大陆地址</item>
|
<item>绕过局域网及中国大陆地址</item>
|
||||||
|
<item>仅代理中国大陆无法访问的地址</item>
|
||||||
|
<item>仅代理中国大陆地址</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string name="action_apply_all">应用设置到所有配置文件</string>
|
<string name="action_apply_all">应用设置到所有配置文件</string>
|
||||||
|
|||||||
@@ -112,6 +112,8 @@
|
|||||||
<item>略過區域網路位址</item>
|
<item>略過區域網路位址</item>
|
||||||
<item>略過中國大陸位址</item>
|
<item>略過中國大陸位址</item>
|
||||||
<item>略過區域網路及中國大陸位址</item>
|
<item>略過區域網路及中國大陸位址</item>
|
||||||
|
<item>僅代理大陸屏蔽位址</item>
|
||||||
|
<item>僅代理大陸位址</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string name="action_apply_all">應用設置到所有配置文件</string>
|
<string name="action_apply_all">應用設置到所有配置文件</string>
|
||||||
|
|||||||
@@ -38,18 +38,13 @@
|
|||||||
<item>chacha20-ietf</item>
|
<item>chacha20-ietf</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="route_entry">
|
|
||||||
<item>All</item>
|
|
||||||
<item>Bypass LAN</item>
|
|
||||||
<item>Bypass China</item>
|
|
||||||
<item>Bypass LAN & China</item>
|
|
||||||
</string-array>
|
|
||||||
|
|
||||||
<string-array name="route_value">
|
<string-array name="route_value">
|
||||||
<item>all</item>
|
<item>all</item>
|
||||||
<item>bypass-lan</item>
|
<item>bypass-lan</item>
|
||||||
<item>bypass-china</item>
|
<item>bypass-china</item>
|
||||||
<item>bypass-lan-china</item>
|
<item>bypass-lan-china</item>
|
||||||
|
<item>gfwlist</item>
|
||||||
|
<item>china-list</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="private_route">
|
<string-array name="private_route">
|
||||||
|
|||||||
@@ -52,6 +52,14 @@
|
|||||||
<string name="auto_set_gfwlist_summary">Bypass all sites located in China
|
<string name="auto_set_gfwlist_summary">Bypass all sites located in China
|
||||||
</string>
|
</string>
|
||||||
<string name="route_list">Route</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 & China</item>
|
||||||
|
<item>GFW List</item>
|
||||||
|
<item>China List</item>
|
||||||
|
</string-array>
|
||||||
<string name="proxied_apps">Per-App Proxy</string>
|
<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="proxied_apps_summary">Set proxy for selected apps, requires NAT mode under Android 4.x</string>
|
||||||
<string name="on">On</string>
|
<string name="on">On</string>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Material" parent="Theme.AppCompat.Light.NoActionBar">
|
<style name="Theme.Material" parent="Theme.AppCompat.Light.NoActionBar">
|
||||||
|
<!--suppress NewApi -->
|
||||||
<item name="android:navigationBarColor">@color/material_accent_700</item>
|
<item name="android:navigationBarColor">@color/material_accent_700</item>
|
||||||
<item name="colorAccent">@color/material_accent_500</item>
|
<item name="colorAccent">@color/material_accent_500</item>
|
||||||
<item name="colorButtonNormal">@color/material_accent_500</item>
|
<item name="colorButtonNormal">@color/material_accent_500</item>
|
||||||
|
|||||||
@@ -112,7 +112,6 @@
|
|||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="tcp_fastopen"
|
android:key="tcp_fastopen"
|
||||||
android:persistent="false"
|
|
||||||
android:summary="@string/tcp_fastopen_summary"
|
android:summary="@string/tcp_fastopen_summary"
|
||||||
android:title="TCP Fast Open"/>
|
android:title="TCP Fast Open"/>
|
||||||
|
|
||||||
|
|||||||
@@ -46,14 +46,13 @@ import android.content._
|
|||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.{Bundle, Handler}
|
import android.os.{Bundle, Handler}
|
||||||
import android.preference.PreferenceManager
|
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.support.v7.widget.Toolbar.OnMenuItemClickListener
|
import android.support.v7.widget.Toolbar.OnMenuItemClickListener
|
||||||
import android.support.v7.widget.{DefaultItemAnimator, LinearLayoutManager, RecyclerView, Toolbar}
|
import android.support.v7.widget.{DefaultItemAnimator, LinearLayoutManager, RecyclerView, Toolbar}
|
||||||
import android.view._
|
import android.view._
|
||||||
import android.widget._
|
import android.widget._
|
||||||
import com.github.shadowsocks.utils.{Key, Utils}
|
|
||||||
import com.github.shadowsocks.ShadowsocksApplication.app
|
import com.github.shadowsocks.ShadowsocksApplication.app
|
||||||
|
import com.github.shadowsocks.utils.{Key, Utils}
|
||||||
|
|
||||||
import scala.collection.JavaConversions._
|
import scala.collection.JavaConversions._
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
@@ -143,7 +142,7 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener {
|
|||||||
private var loadingView: View = _
|
private var loadingView: View = _
|
||||||
private val appsLoading = new AtomicBoolean
|
private val appsLoading = new AtomicBoolean
|
||||||
private var handler: Handler = _
|
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]
|
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) {
|
protected override def onCreate(savedInstanceState: Bundle) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
if (profile == null) finish()
|
||||||
|
|
||||||
handler = new Handler()
|
handler = new Handler()
|
||||||
|
|
||||||
this.setContentView(R.layout.layout_apps)
|
this.setContentView(R.layout.layout_apps)
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ trait BaseService extends Service {
|
|||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def getProfileName: String = if (profile == null) null else profile.name
|
||||||
|
|
||||||
override def unregisterCallback(cb: IShadowsocksServiceCallback) {
|
override def unregisterCallback(cb: IShadowsocksServiceCallback) {
|
||||||
if (cb != null && callbacks.unregister(cb)) {
|
if (cb != null && callbacks.unregister(cb)) {
|
||||||
callbacksCount -= 1
|
callbacksCount -= 1
|
||||||
@@ -282,7 +284,7 @@ trait BaseService extends Service {
|
|||||||
val n = callbacks.beginBroadcast()
|
val n = callbacks.beginBroadcast()
|
||||||
for (i <- 0 until n) {
|
for (i <- 0 until n) {
|
||||||
try {
|
try {
|
||||||
callbacks.getBroadcastItem(i).stateChanged(s, msg)
|
callbacks.getBroadcastItem(i).stateChanged(s, binder.getProfileName, msg)
|
||||||
} catch {
|
} catch {
|
||||||
case _: Exception => // Ignore
|
case _: Exception => // Ignore
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,18 +39,35 @@
|
|||||||
|
|
||||||
package com.github.shadowsocks
|
package com.github.shadowsocks
|
||||||
|
|
||||||
import java.io.{IOException, InputStream, OutputStream}
|
import java.io._
|
||||||
import java.lang.System.currentTimeMillis
|
import java.lang.System.currentTimeMillis
|
||||||
import java.util.concurrent.Semaphore
|
import java.util.concurrent.Semaphore
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
|
||||||
import scala.collection.JavaConversions._
|
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
|
* @author ayanamist@gmail.com
|
||||||
*/
|
*/
|
||||||
class GuardedProcess(cmd: Seq[String]) extends Process {
|
class GuardedProcess(cmd: Seq[String]) {
|
||||||
private val TAG = classOf[GuardedProcess].getSimpleName
|
private val TAG = classOf[GuardedProcess].getSimpleName
|
||||||
|
|
||||||
@volatile private var guardThread: Thread = _
|
@volatile private var guardThread: Thread = _
|
||||||
@@ -72,19 +89,25 @@ class GuardedProcess(cmd: Seq[String]) extends Process {
|
|||||||
|
|
||||||
process = new ProcessBuilder(cmd).redirectErrorStream(true).start
|
process = new ProcessBuilder(cmd).redirectErrorStream(true).start
|
||||||
|
|
||||||
|
val is = process.getInputStream
|
||||||
|
new StreamLogger(is, TAG).start
|
||||||
|
|
||||||
if (callback == null) callback = onRestartCallback else callback()
|
if (callback == null) callback = onRestartCallback else callback()
|
||||||
|
|
||||||
semaphore.release
|
semaphore.release
|
||||||
process.waitFor
|
process.waitFor
|
||||||
|
|
||||||
if (isRestart) {
|
this.synchronized {
|
||||||
isRestart = false
|
if (isRestart) {
|
||||||
} else {
|
isRestart = false
|
||||||
if (currentTimeMillis - startTime < 1000) {
|
} else {
|
||||||
Log.w(TAG, "process exit too fast, stop guard: " + cmd)
|
if (currentTimeMillis - startTime < 1000) {
|
||||||
isDestroyed = true
|
Log.w(TAG, "process exit too fast, stop guard: " + cmd)
|
||||||
|
isDestroyed = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
case ignored: InterruptedException =>
|
case ignored: InterruptedException =>
|
||||||
@@ -114,15 +137,12 @@ class GuardedProcess(cmd: Seq[String]) extends Process {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def restart() {
|
def restart() {
|
||||||
isRestart = true
|
this.synchronized {
|
||||||
process.destroy()
|
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])
|
@throws(classOf[InterruptedException])
|
||||||
def waitFor = {
|
def waitFor = {
|
||||||
guardThread.join()
|
guardThread.join()
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ final class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClic
|
|||||||
}).attachToRecyclerView(profilesList)
|
}).attachToRecyclerView(profilesList)
|
||||||
|
|
||||||
attachService(new IShadowsocksServiceCallback.Stub {
|
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) =
|
def trafficUpdated(txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) =
|
||||||
if (selectedItem != null) selectedItem.updateText(txTotal, rxTotal)
|
if (selectedItem != null) selectedItem.updateText(txTotal, rxTotal)
|
||||||
})
|
})
|
||||||
@@ -276,7 +276,7 @@ final class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClic
|
|||||||
updateNfcState()
|
updateNfcState()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onNewIntent(intent: Intent): Unit ={
|
override def onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
handleShareIntent(intent)
|
handleShareIntent(intent)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
|
|||||||
|
|
||||||
// Services
|
// Services
|
||||||
private val callback = new IShadowsocksServiceCallback.Stub {
|
private val callback = new IShadowsocksServiceCallback.Stub {
|
||||||
def stateChanged(s: Int, m: String) {
|
def stateChanged(s: Int, profileName: String, m: String) {
|
||||||
handler.post(() => {
|
handler.post(() => {
|
||||||
s match {
|
s match {
|
||||||
case State.CONNECTING =>
|
case State.CONNECTING =>
|
||||||
@@ -186,8 +186,8 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
|
|||||||
snackbar.show
|
snackbar.show
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!app.settings.getBoolean(BuildConfig.VERSION_NAME, false)) {
|
if (app.settings.getInt(Key.currentVersionCode, -1) != BuildConfig.VERSION_CODE) {
|
||||||
app.editor.putBoolean(BuildConfig.VERSION_NAME, true).apply()
|
app.editor.putInt(Key.currentVersionCode, BuildConfig.VERSION_CODE).apply()
|
||||||
|
|
||||||
recovery()
|
recovery()
|
||||||
|
|
||||||
@@ -514,6 +514,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
|
|||||||
crashRecovery()
|
crashRecovery()
|
||||||
|
|
||||||
copyAssets(System.getABI)
|
copyAssets(System.getABI)
|
||||||
|
copyAssets("acl")
|
||||||
|
|
||||||
val ab = new ArrayBuffer[String]
|
val ab = new ArrayBuffer[String]
|
||||||
for (executable <- EXECUTABLES) {
|
for (executable <- EXECUTABLES) {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ import android.app.Application
|
|||||||
import android.preference.PreferenceManager
|
import android.preference.PreferenceManager
|
||||||
import android.support.v7.app.AppCompatDelegate
|
import android.support.v7.app.AppCompatDelegate
|
||||||
import com.github.shadowsocks.database.{DBHelper, ProfileManager}
|
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.analytics.{GoogleAnalytics, HitBuilders, StandardExceptionParser}
|
||||||
import com.google.android.gms.common.api.ResultCallback
|
import com.google.android.gms.common.api.ResultCallback
|
||||||
import com.google.android.gms.tagmanager.{ContainerHolder, TagManager}
|
import com.google.android.gms.tagmanager.{ContainerHolder, TagManager}
|
||||||
@@ -111,6 +111,8 @@ class ShadowsocksApplication extends Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pending.setResultCallback(callback, 2, TimeUnit.SECONDS)
|
pending.setResultCallback(callback, 2, TimeUnit.SECONDS)
|
||||||
|
|
||||||
|
TcpFastOpen.enabled(settings.getBoolean(Key.tfo, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
def refreshContainerHolder {
|
def refreshContainerHolder {
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
package com.github.shadowsocks
|
package com.github.shadowsocks
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.Process
|
|
||||||
import java.net.{Inet6Address, InetAddress}
|
import java.net.{Inet6Address, InetAddress}
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@@ -65,22 +64,24 @@ class ShadowsocksNatService extends BaseService {
|
|||||||
private var notification: ShadowsocksNotification = _
|
private var notification: ShadowsocksNotification = _
|
||||||
val myUid = android.os.Process.myUid()
|
val myUid = android.os.Process.myUid()
|
||||||
|
|
||||||
var sslocalProcess: Process = _
|
var sslocalProcess: GuardedProcess = _
|
||||||
var sstunnelProcess: Process = _
|
var sstunnelProcess: GuardedProcess = _
|
||||||
var redsocksProcess: Process = _
|
var redsocksProcess: GuardedProcess = _
|
||||||
var pdnsdProcess: Process = _
|
var pdnsdProcess: GuardedProcess = _
|
||||||
var su: Shell.Interactive = _
|
var su: Shell.Interactive = _
|
||||||
|
|
||||||
def startShadowsocksDaemon() {
|
def startShadowsocksDaemon() {
|
||||||
if (profile.route != Route.ALL) {
|
if (profile.route != Route.ALL && profile.route != Route.GFWLIST) {
|
||||||
val acl: Array[Array[String]] = profile.route match {
|
val acl: Array[String] = profile.route match {
|
||||||
case Route.BYPASS_LAN => Array(getResources.getStringArray(R.array.private_route))
|
case Route.BYPASS_LAN => getResources.getStringArray(R.array.private_route)
|
||||||
case Route.BYPASS_CHN => Array(getResources.getStringArray(R.array.chn_route))
|
case Route.BYPASS_CHN => getResources.getStringArray(R.array.chn_route)
|
||||||
case Route.BYPASS_LAN_CHN =>
|
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 => {
|
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) {
|
if (profile.route != Route.ALL) {
|
||||||
cmd += "--acl"
|
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(" "))
|
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
|
||||||
@@ -185,12 +189,23 @@ class ShadowsocksNatService extends BaseService {
|
|||||||
|
|
||||||
def startDnsDaemon() {
|
def startDnsDaemon() {
|
||||||
|
|
||||||
val conf = if (profile.route == Route.BYPASS_CHN || profile.route == Route.BYPASS_LAN_CHN) {
|
val conf = profile.route match {
|
||||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
case Route.BYPASS_CHN | Route.BYPASS_LAN_CHN => {
|
||||||
"127.0.0.1", profile.localPort + 53, getBlackList, profile.localPort + 63, "")
|
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
||||||
} else {
|
"127.0.0.1", profile.localPort + 53, getBlackList, profile.localPort + 63, "")
|
||||||
ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
}
|
||||||
"127.0.0.1", profile.localPort + 53, 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 => {
|
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)
|
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, _) =>
|
su = new Shell.Builder().useSU().setWantSTDERR(true).setWatchdogTimeout(10).open((_, exitCode, _) =>
|
||||||
if (exitCode == 0) super.startRunner(profile) else {
|
if (exitCode == 0) super.startRunner(profile) else {
|
||||||
if (su != null) {
|
if (su != null) {
|
||||||
Log.wtf(TAG, "libsuperuser#55 has been fixed. Please remove the redundant code.")
|
|
||||||
su.close()
|
su.close()
|
||||||
su = null
|
su = null
|
||||||
}
|
}
|
||||||
super.stopRunner(true, getString(R.string.nat_no_root))
|
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() {
|
override def connect() {
|
||||||
super.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 val keyGuard = service.getSystemService(Context.KEYGUARD_SERVICE).asInstanceOf[KeyguardManager]
|
||||||
private lazy val nm = service.getSystemService(Context.NOTIFICATION_SERVICE).asInstanceOf[NotificationManager]
|
private lazy val nm = service.getSystemService(Context.NOTIFICATION_SERVICE).asInstanceOf[NotificationManager]
|
||||||
private lazy val callback = new Stub {
|
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) {
|
override def trafficUpdated(txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) {
|
||||||
val txr = TrafficMonitor.formatTraffic(txRate)
|
val txr = TrafficMonitor.formatTraffic(txRate)
|
||||||
val rxr = TrafficMonitor.formatTraffic(rxRate)
|
val rxr = TrafficMonitor.formatTraffic(rxRate)
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class ShadowsocksQuickSwitchActivity extends AppCompatActivity {
|
|||||||
profilesList.setItemAnimator(new DefaultItemAnimator)
|
profilesList.setItemAnimator(new DefaultItemAnimator)
|
||||||
profilesList.setAdapter(profilesAdapter)
|
profilesList.setAdapter(profilesAdapter)
|
||||||
if (app.profileId >= 0) lm.scrollToPosition(profilesAdapter.profiles.zipWithIndex.collectFirst {
|
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))
|
}.getOrElse(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.content.{Intent, SharedPreferences}
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.preference.{Preference, PreferenceFragment, SwitchPreference}
|
import android.preference.{Preference, PreferenceFragment, SwitchPreference}
|
||||||
|
import android.support.design.widget.Snackbar
|
||||||
import android.support.v7.app.AlertDialog
|
import android.support.v7.app.AlertDialog
|
||||||
import android.webkit.{WebView, WebViewClient}
|
import android.webkit.{WebView, WebViewClient}
|
||||||
import com.github.shadowsocks.ShadowsocksApplication.app
|
import com.github.shadowsocks.ShadowsocksApplication.app
|
||||||
@@ -154,11 +155,13 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
|
|||||||
}
|
}
|
||||||
switch.setChecked(BootReceiver.getEnabled(activity))
|
switch.setChecked(BootReceiver.getEnabled(activity))
|
||||||
|
|
||||||
val tfo = findPreference("tcp_fastopen").asInstanceOf[SwitchPreference]
|
val tfo = findPreference(Key.tfo).asInstanceOf[SwitchPreference]
|
||||||
tfo.setChecked(TcpFastOpen.sendEnabled)
|
tfo.setChecked(TcpFastOpen.sendEnabled)
|
||||||
tfo.setOnPreferenceChangeListener((_, v) => {
|
tfo.setOnPreferenceChangeListener((_, v) => {
|
||||||
val value = v.asInstanceOf[Boolean]
|
val value = v.asInstanceOf[Boolean]
|
||||||
TcpFastOpen.enabled(value)
|
val result = TcpFastOpen.enabled(value)
|
||||||
|
if (result != null && result != "Success.")
|
||||||
|
Snackbar.make(activity.findViewById(android.R.id.content), result, Snackbar.LENGTH_LONG).show()
|
||||||
value == TcpFastOpen.sendEnabled
|
value == TcpFastOpen.sendEnabled
|
||||||
})
|
})
|
||||||
if (!TcpFastOpen.supported) {
|
if (!TcpFastOpen.supported) {
|
||||||
@@ -204,7 +207,19 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
|
|||||||
}
|
}
|
||||||
|
|
||||||
def refreshProfile() {
|
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)
|
isProxyApps.setChecked(profile.proxyApps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.graphics.drawable.Icon
|
|||||||
import android.service.quicksettings.{Tile, TileService}
|
import android.service.quicksettings.{Tile, TileService}
|
||||||
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
|
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
|
||||||
import com.github.shadowsocks.utils.{State, Utils}
|
import com.github.shadowsocks.utils.{State, Utils}
|
||||||
import com.github.shadowsocks.ShadowsocksApplication.app
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Mygod
|
* @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 iconConnected = Icon.createWithResource(this, R.drawable.ic_start_connected)
|
||||||
private lazy val callback = new IShadowsocksServiceCallback.Stub {
|
private lazy val callback = new IShadowsocksServiceCallback.Stub {
|
||||||
def trafficUpdated(txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) = ()
|
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
|
val tile = getQsTile
|
||||||
if (tile != null) {
|
if (tile != null) {
|
||||||
state match {
|
state match {
|
||||||
@@ -33,10 +32,7 @@ final class ShadowsocksTileService extends TileService with ServiceBoundContext
|
|||||||
tile.setState(Tile.STATE_INACTIVE)
|
tile.setState(Tile.STATE_INACTIVE)
|
||||||
case State.CONNECTED =>
|
case State.CONNECTED =>
|
||||||
tile.setIcon(iconConnected)
|
tile.setIcon(iconConnected)
|
||||||
tile.setLabel(app.currentProfile match {
|
tile.setLabel(if (profileName == null) getString(R.string.app_name) else profileName)
|
||||||
case Some(profile) => profile.name
|
|
||||||
case None => getString(R.string.app_name)
|
|
||||||
})
|
|
||||||
tile.setState(Tile.STATE_ACTIVE)
|
tile.setState(Tile.STATE_ACTIVE)
|
||||||
case _ =>
|
case _ =>
|
||||||
tile.setIcon(iconBusy)
|
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 {
|
override def onCreate {
|
||||||
super.onCreate
|
super.onCreate
|
||||||
|
|||||||
@@ -40,9 +40,9 @@
|
|||||||
package com.github.shadowsocks
|
package com.github.shadowsocks
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.Process
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content._
|
import android.content._
|
||||||
import android.content.pm.PackageManager.NameNotFoundException
|
import android.content.pm.PackageManager.NameNotFoundException
|
||||||
import android.net.VpnService
|
import android.net.VpnService
|
||||||
@@ -63,10 +63,10 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
|||||||
var vpnThread: ShadowsocksVpnThread = _
|
var vpnThread: ShadowsocksVpnThread = _
|
||||||
private var notification: ShadowsocksNotification = _
|
private var notification: ShadowsocksNotification = _
|
||||||
|
|
||||||
var sslocalProcess: Process = _
|
var sslocalProcess: GuardedProcess = _
|
||||||
var sstunnelProcess: Process = _
|
var sstunnelProcess: GuardedProcess = _
|
||||||
var pdnsdProcess: Process = _
|
var pdnsdProcess: GuardedProcess = _
|
||||||
var tun2socksProcess: Process = _
|
var tun2socksProcess: GuardedProcess = _
|
||||||
|
|
||||||
override def onBind(intent: Intent): IBinder = {
|
override def onBind(intent: Intent): IBinder = {
|
||||||
val action = intent.getAction
|
val action = intent.getAction
|
||||||
@@ -226,15 +226,17 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def startShadowsocksDaemon() {
|
def startShadowsocksDaemon() {
|
||||||
if (profile.route != Route.ALL) {
|
if (profile.route != Route.ALL && profile.route != Route.GFWLIST) {
|
||||||
val acl: Array[Array[String]] = profile.route match {
|
val acl: Array[String] = profile.route match {
|
||||||
case Route.BYPASS_LAN => Array(getResources.getStringArray(R.array.private_route))
|
case Route.BYPASS_LAN => getResources.getStringArray(R.array.private_route)
|
||||||
case Route.BYPASS_CHN => Array(getResources.getStringArray(R.array.chn_route))
|
case Route.BYPASS_CHN => getResources.getStringArray(R.array.chn_route)
|
||||||
case Route.BYPASS_LAN_CHN =>
|
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 => {
|
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) {
|
if (profile.route != Route.ALL) {
|
||||||
cmd += "--acl"
|
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"
|
if (TcpFastOpen.sendEnabled) cmd += "--fast-open"
|
||||||
@@ -303,11 +308,20 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
|||||||
|
|
||||||
def startDnsDaemon() {
|
def startDnsDaemon() {
|
||||||
val ipv6 = if (profile.ipv6) "" else "reject = ::/0;"
|
val ipv6 = if (profile.ipv6) "" else "reject = ::/0;"
|
||||||
val conf = {
|
val conf = profile.route match {
|
||||||
if (profile.route == Route.BYPASS_CHN || profile.route == Route.BYPASS_LAN_CHN) {
|
case Route.BYPASS_CHN | Route.BYPASS_LAN_CHN => {
|
||||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
||||||
"0.0.0.0", profile.localPort + 53, getBlackList, profile.localPort + 63, ipv6)
|
"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,
|
ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
||||||
"0.0.0.0", profile.localPort + 53, profile.localPort + 63, ipv6)
|
"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()
|
pdnsdProcess = new GuardedProcess(cmd).start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint(Array("NewApi"))
|
||||||
def startVpn(): Int = {
|
def startVpn(): Int = {
|
||||||
|
|
||||||
val builder = new Builder()
|
val builder = new Builder()
|
||||||
@@ -329,7 +344,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
|||||||
.setSession(profile.name)
|
.setSession(profile.name)
|
||||||
.setMtu(VPN_MTU)
|
.setMtu(VPN_MTU)
|
||||||
.addAddress(PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1"), 24)
|
.addAddress(PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1"), 24)
|
||||||
.addDnsServer("8.8.8.8")
|
|
||||||
|
builder.addDnsServer("8.8.8.8")
|
||||||
|
|
||||||
if (profile.ipv6) {
|
if (profile.ipv6) {
|
||||||
builder.addAddress(PRIVATE_VLAN6.formatLocal(Locale.ENGLISH, "1"), 126)
|
builder.addAddress(PRIVATE_VLAN6.formatLocal(Locale.ENGLISH, "1"), 126)
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ object ConfigUtils {
|
|||||||
|
|
|
|
||||||
|server {
|
|server {
|
||||||
| label = "china-servers";
|
| 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;
|
| timeout = 4;
|
||||||
| exclude = %s;
|
| exclude = %s;
|
||||||
| policy = included;
|
| policy = included;
|
||||||
@@ -141,6 +141,47 @@ object ConfigUtils {
|
|||||||
| soa=localhost,root.localhost,42,86400,900,86400,86400;
|
| soa=localhost,root.localhost,42,86400,900,86400,86400;
|
||||||
|}
|
|}
|
||||||
""".stripMargin
|
""".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 {
|
object Key {
|
||||||
@@ -171,6 +212,9 @@ object Key {
|
|||||||
val kcp = "kcp"
|
val kcp = "kcp"
|
||||||
val kcpPort = "kcpPort"
|
val kcpPort = "kcpPort"
|
||||||
val kcpcli = "kcpcli"
|
val kcpcli = "kcpcli"
|
||||||
|
|
||||||
|
val tfo = "tcp_fastopen"
|
||||||
|
val currentVersionCode = "currentVersionCode"
|
||||||
}
|
}
|
||||||
|
|
||||||
object State {
|
object State {
|
||||||
@@ -192,4 +236,6 @@ object Route {
|
|||||||
val BYPASS_LAN = "bypass-lan"
|
val BYPASS_LAN = "bypass-lan"
|
||||||
val BYPASS_CHN = "bypass-china"
|
val BYPASS_CHN = "bypass-china"
|
||||||
val BYPASS_LAN_CHN = "bypass-lan-china"
|
val BYPASS_LAN_CHN = "bypass-lan-china"
|
||||||
|
val GFWLIST = "gfwlist"
|
||||||
|
val CHINALIST = "china-list"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import java.io.File
|
|||||||
|
|
||||||
import eu.chainfire.libsuperuser.Shell
|
import eu.chainfire.libsuperuser.Shell
|
||||||
|
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Mygod
|
* @author Mygod
|
||||||
*/
|
*/
|
||||||
@@ -26,11 +28,13 @@ object TcpFastOpen {
|
|||||||
file.canRead && (Utils.readAllLines(file).toInt & 1) > 0
|
file.canRead && (Utils.readAllLines(file).toInt & 1) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
def enabled(value: Boolean) = if (supported) {
|
def enabled(value: Boolean): String = if (sendEnabled != value) {
|
||||||
val fastopen = "echo " + (if (value) 3 else 0) + " > /proc/sys/net/ipv4/tcp_fastopen"
|
val res = Shell.run("su", Array(
|
||||||
Shell.SU.run(Array(
|
"if echo " + (if (value) 3 else 0) + " > /proc/sys/net/ipv4/tcp_fastopen; then",
|
||||||
"mount -o remount,rw /system && " + fastopen + " && echo '#!/system/bin/sh\n" + fastopen +
|
" echo Success.",
|
||||||
"' > /etc/init.d/tcp_fastopen && chmod 755 /etc/init.d/tcp_fastopen",
|
"else",
|
||||||
"mount -o remount,ro /system"))
|
" echo Failed.",
|
||||||
}
|
"fi"), null, true)
|
||||||
|
if (res != null) res.asScala.mkString("\n") else null
|
||||||
|
} else null
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user