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