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
0b8114ad
Commit
0b8114ad
authored
Feb 09, 2014
by
Max Lv
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #64 from shadowsocks/aidl
AIDL
parents
abf050a4
59d304ea
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
794 additions
and
697 deletions
+794
-697
src/main/AndroidManifest.xml
src/main/AndroidManifest.xml
+9
-4
src/main/java/com/github/shadowsocks/aidl/Config.aidl
src/main/java/com/github/shadowsocks/aidl/Config.aidl
+3
-0
src/main/java/com/github/shadowsocks/aidl/Config.java
src/main/java/com/github/shadowsocks/aidl/Config.java
+86
-0
src/main/java/com/github/shadowsocks/aidl/IShadowsocksService.aidl
...java/com/github/shadowsocks/aidl/IShadowsocksService.aidl
+13
-0
src/main/java/com/github/shadowsocks/aidl/IShadowsocksServiceCallback.aidl
.../github/shadowsocks/aidl/IShadowsocksServiceCallback.aidl
+5
-0
src/main/res/layout/layout_switch.xml
src/main/res/layout/layout_switch.xml
+1
-0
src/main/scala/com/github/shadowsocks/BaseService.scala
src/main/scala/com/github/shadowsocks/BaseService.scala
+88
-0
src/main/scala/com/github/shadowsocks/Shadowsocks.scala
src/main/scala/com/github/shadowsocks/Shadowsocks.scala
+208
-176
src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala
.../scala/com/github/shadowsocks/ShadowsocksNatService.scala
+163
-217
src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala
...in/scala/com/github/shadowsocks/ShadowsocksReceiver.scala
+2
-19
src/main/scala/com/github/shadowsocks/ShadowsocksRunnerActivity.scala
...la/com/github/shadowsocks/ShadowsocksRunnerActivity.scala
+55
-18
src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala
.../scala/com/github/shadowsocks/ShadowsocksVpnService.scala
+112
-169
src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala
...main/scala/com/github/shadowsocks/utils/ConfigUtils.scala
+33
-7
src/main/scala/com/github/shadowsocks/utils/Constants.scala
src/main/scala/com/github/shadowsocks/utils/Constants.scala
+16
-87
No files found.
src/main/AndroidManifest.xml
View file @
0b8114ad
...
@@ -54,7 +54,7 @@
...
@@ -54,7 +54,7 @@
</activity>
</activity>
<activity
<activity
android:name=
".Shadow
Vpn
Activity"
android:name=
".Shadow
socksRunner
Activity"
android:theme=
"@style/PopupTheme"
android:theme=
"@style/PopupTheme"
android:launchMode=
"singleTask"
>
android:launchMode=
"singleTask"
>
</activity>
</activity>
...
@@ -70,17 +70,22 @@
...
@@ -70,17 +70,22 @@
</activity>
</activity>
<service
<service
android:name=
".ShadowsocksService"
android:name=
".Shadowsocks
Nat
Service"
android:process=
":proxy"
android:process=
":proxy"
android:exported=
"false"
/>
android:exported=
"false"
>
<intent-filter>
<action
android:name=
"com.github.shadowsocks.ShadowsocksNatService"
/>
</intent-filter>
</service>
<service
<service
android:name=
".ShadowVpnService"
android:name=
".Shadow
socks
VpnService"
android:label=
"@string/app_name"
android:label=
"@string/app_name"
android:process=
":vpn"
android:process=
":vpn"
android:permission=
"android.permission.BIND_VPN_SERVICE"
android:permission=
"android.permission.BIND_VPN_SERVICE"
android:exported=
"false"
>
android:exported=
"false"
>
<intent-filter>
<intent-filter>
<action
android:name=
"com.github.shadowsocks.ShadowsocksVpnService"
/>
<action
android:name=
"android.net.VpnService"
/>
<action
android:name=
"android.net.VpnService"
/>
</intent-filter>
</intent-filter>
</service>
</service>
...
...
src/main/java/com/github/shadowsocks/aidl/Config.aidl
0 → 100644
View file @
0b8114ad
package
com
.
github
.
shadowsocks
.
aidl
;
parcelable
Config
;
\ No newline at end of file
src/main/java/com/github/shadowsocks/aidl/Config.java
0 → 100644
View file @
0b8114ad
package
com.github.shadowsocks.aidl
;
import
android.os.Parcel
;
import
android.os.Parcelable
;
public
class
Config
implements
Parcelable
{
public
boolean
isGlobalProxy
=
true
;
public
boolean
isGFWList
=
true
;
public
boolean
isBypassApps
=
false
;
public
boolean
isTrafficStat
=
false
;
public
String
profileName
=
"Untitled"
;
public
String
proxy
=
"127.0.0.1"
;
public
String
sitekey
=
"null"
;
public
String
encMethod
=
"rc4"
;
public
String
proxiedAppString
=
""
;
public
int
remotePort
=
1984
;
public
int
localPort
=
1080
;
public
static
final
Parcelable
.
Creator
<
Config
>
CREATOR
=
new
Parcelable
.
Creator
<
Config
>()
{
public
Config
createFromParcel
(
Parcel
in
)
{
return
new
Config
(
in
);
}
public
Config
[]
newArray
(
int
size
)
{
return
new
Config
[
size
];
}
};
public
Config
(
boolean
isGlobalProxy
,
boolean
isGFWList
,
boolean
isBypassApps
,
boolean
isTrafficStat
,
String
profileName
,
String
proxy
,
String
sitekey
,
String
encMethod
,
String
proxiedAppString
,
int
remotePort
,
int
localPort
)
{
this
.
isGlobalProxy
=
isGlobalProxy
;
this
.
isGFWList
=
isGFWList
;
this
.
isBypassApps
=
isBypassApps
;
this
.
isTrafficStat
=
isTrafficStat
;
this
.
profileName
=
profileName
;
this
.
proxy
=
proxy
;
this
.
sitekey
=
sitekey
;
this
.
encMethod
=
encMethod
;
this
.
proxiedAppString
=
proxiedAppString
;
this
.
remotePort
=
remotePort
;
this
.
localPort
=
localPort
;
}
private
Config
(
Parcel
in
)
{
readFromParcel
(
in
);
}
public
void
readFromParcel
(
Parcel
in
)
{
isGlobalProxy
=
in
.
readInt
()
==
1
;
isGFWList
=
in
.
readInt
()
==
1
;
isBypassApps
=
in
.
readInt
()
==
1
;
isTrafficStat
=
in
.
readInt
()
==
1
;
profileName
=
in
.
readString
();
proxy
=
in
.
readString
();
sitekey
=
in
.
readString
();
encMethod
=
in
.
readString
();
proxiedAppString
=
in
.
readString
();
remotePort
=
in
.
readInt
();
localPort
=
in
.
readInt
();
}
@Override
public
int
describeContents
()
{
return
0
;
}
@Override
public
void
writeToParcel
(
Parcel
out
,
int
flags
)
{
out
.
writeInt
(
isGlobalProxy
?
1
:
0
);
out
.
writeInt
(
isGFWList
?
1
:
0
);
out
.
writeInt
(
isBypassApps
?
1
:
0
);
out
.
writeInt
(
isTrafficStat
?
1
:
0
);
out
.
writeString
(
profileName
);
out
.
writeString
(
proxy
);
out
.
writeString
(
sitekey
);
out
.
writeString
(
encMethod
);
out
.
writeString
(
proxiedAppString
);
out
.
writeInt
(
remotePort
);
out
.
writeInt
(
localPort
);
}
}
src/main/java/com/github/shadowsocks/aidl/IShadowsocksService.aidl
0 → 100644
View file @
0b8114ad
package
com
.
github
.
shadowsocks
.
aidl
;
import
com
.
github
.
shadowsocks
.
aidl
.
Config
;
import
com
.
github
.
shadowsocks
.
aidl
.
IShadowsocksServiceCallback
;
interface
IShadowsocksService
{
int
getMode
();
int
getState
();
void
start
(
in
Config
config
);
void
stop
();
void
registerCallback
(
IShadowsocksServiceCallback
cb
);
void
unregisterCallback
(
IShadowsocksServiceCallback
cb
);
}
\ No newline at end of file
src/main/java/com/github/shadowsocks/aidl/IShadowsocksServiceCallback.aidl
0 → 100644
View file @
0b8114ad
package
com
.
github
.
shadowsocks
.
aidl
;
interface
IShadowsocksServiceCallback
{
void
stateChanged
(
int
state
,
String
msg
);
}
\ No newline at end of file
src/main/res/layout/layout_switch.xml
View file @
0b8114ad
...
@@ -17,6 +17,7 @@
...
@@ -17,6 +17,7 @@
<org.jraf.android.backport.switchwidget.Switch
<org.jraf.android.backport.switchwidget.Switch
android:id=
"@+id/switchButton"
android:id=
"@+id/switchButton"
android:enabled=
"false"
android:layout_width=
"wrap_content"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_alignParentRight=
"true"
android:layout_alignParentRight=
"true"
...
...
src/main/scala/com/github/shadowsocks/BaseService.scala
0 → 100644
View file @
0b8114ad
package
com.github.shadowsocks
import
android.os.
{
Handler
,
RemoteCallbackList
}
import
com.github.shadowsocks.aidl.
{
Config
,
IShadowsocksService
,
IShadowsocksServiceCallback
}
import
com.github.shadowsocks.utils.
{
Path
,
State
}
import
java.io.
{
IOException
,
FileNotFoundException
,
FileReader
,
BufferedReader
}
import
android.util.Log
import
android.app.Notification
import
android.content.Context
trait
BaseService
{
var
state
=
State
.
INIT
final
val
callbacks
=
new
RemoteCallbackList
[
IShadowsocksServiceCallback
]
protected
val
binder
=
new
IShadowsocksService
.
Stub
{
override
def
getMode
:
Int
=
{
getServiceMode
}
override
def
getState
:
Int
=
{
state
}
override
def
unregisterCallback
(
cb
:
IShadowsocksServiceCallback
)
{
if
(
cb
!=
null
)
callbacks
.
unregister
(
cb
)
}
override
def
registerCallback
(
cb
:
IShadowsocksServiceCallback
)
{
if
(
cb
!=
null
)
callbacks
.
register
(
cb
)
}
override
def
stop
()
{
stopRunner
()
}
override
def
start
(
config
:
Config
)
{
startRunner
(
config
)
}
}
def
startRunner
(
config
:
Config
)
def
stopRunner
()
def
getServiceMode
:
Int
def
getTag
:
String
def
getContext
:
Context
def
changeState
(
s
:
Int
)
{
changeState
(
s
,
null
)
}
protected
def
changeState
(
s
:
Int
,
msg
:
String
)
{
val
handler
=
new
Handler
(
getContext
.
getMainLooper
)
handler
.
post
(
new
Runnable
{
override
def
run
()
{
if
(
state
!=
s
)
{
val
n
=
callbacks
.
beginBroadcast
()
for
(
i
<-
0
to
n
-
1
)
{
callbacks
.
getBroadcastItem
(
i
).
stateChanged
(
s
,
msg
)
}
callbacks
.
finishBroadcast
()
state
=
s
}
}
})
}
def
getPid
(
name
:
String
)
:
Int
=
{
try
{
val
reader
:
BufferedReader
=
new
BufferedReader
(
new
FileReader
(
Path
.
BASE
+
name
+
".pid"
))
val
line
=
reader
.
readLine
return
Integer
.
valueOf
(
line
)
}
catch
{
case
e
:
FileNotFoundException
=>
Log
.
e
(
getTag
,
"Cannot open pid file: "
+
name
)
case
e
:
IOException
=>
Log
.
e
(
getTag
,
"Cannot read pid file: "
+
name
)
case
e
:
NumberFormatException
=>
Log
.
e
(
getTag
,
"Invalid pid"
,
e
)
}
-
1
}
def
initSoundVibrateLights
(
notification
:
Notification
)
{
notification
.
sound
=
null
}
}
src/main/scala/com/github/shadowsocks/Shadowsocks.scala
View file @
0b8114ad
...
@@ -67,12 +67,11 @@ import scala.collection.mutable.ListBuffer
...
@@ -67,12 +67,11 @@ import scala.collection.mutable.ListBuffer
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.Profile
import
com.nostra13.universalimageloader.core.download.BaseImageDownloader
import
com.nostra13.universalimageloader.core.download.BaseImageDownloader
import
com.github.shadowsocks.preferences.
{
ProfileEditTextPreference
,
PasswordEditTextPreference
,
SummaryEditTextPreference
}
import
com.github.shadowsocks.preferences.
{
ProfileEditTextPreference
,
PasswordEditTextPreference
,
SummaryEditTextPreference
}
import
com.github.shadowsocks.database.Item
import
com.github.shadowsocks.database.Category
import
com.github.shadowsocks.utils._
import
com.github.shadowsocks.utils._
import
com.github.shadowsocks.database.Item
import
com.github.shadowsocks.database.Item
import
com.github.shadowsocks.database.Category
import
com.github.shadowsocks.database.Category
import
com.google.zxing.integration.android.IntentIntegrator
import
com.google.zxing.integration.android.IntentIntegrator
import
com.github.shadowsocks.aidl.
{
IShadowsocksServiceCallback
,
IShadowsocksService
}
class
ProfileIconDownloader
(
context
:
Context
,
connectTimeout
:
Int
,
readTimeout
:
Int
)
class
ProfileIconDownloader
(
context
:
Context
,
connectTimeout
:
Int
,
readTimeout
:
Int
)
extends
BaseImageDownloader
(
context
,
connectTimeout
,
readTimeout
)
{
extends
BaseImageDownloader
(
context
,
connectTimeout
,
readTimeout
)
{
...
@@ -103,12 +102,11 @@ object Typefaces {
...
@@ -103,12 +102,11 @@ object Typefaces {
val
t
:
Typeface
=
Typeface
.
createFromAsset
(
c
.
getAssets
,
assetPath
)
val
t
:
Typeface
=
Typeface
.
createFromAsset
(
c
.
getAssets
,
assetPath
)
cache
.
put
(
assetPath
,
t
)
cache
.
put
(
assetPath
,
t
)
}
catch
{
}
catch
{
case
e
:
Exception
=>
{
case
e
:
Exception
=>
Log
.
e
(
TAG
,
"Could not get typeface '"
+
assetPath
+
"' because "
+
e
.
getMessage
)
Log
.
e
(
TAG
,
"Could not get typeface '"
+
assetPath
+
"' because "
+
e
.
getMessage
)
return
null
return
null
}
}
}
}
}
return
cache
.
get
(
assetPath
)
return
cache
.
get
(
assetPath
)
}
}
}
}
...
@@ -131,8 +129,7 @@ object Shadowsocks {
...
@@ -131,8 +129,7 @@ object Shadowsocks {
// Flags
// Flags
var
vpnEnabled
=
-
1
var
vpnEnabled
=
-
1
// Help functions
// Helper functions
def
updateListPreference
(
pref
:
Preference
,
value
:
String
)
{
def
updateListPreference
(
pref
:
Preference
,
value
:
String
)
{
pref
.
setSummary
(
value
)
pref
.
setSummary
(
value
)
pref
.
asInstanceOf
[
ListPreference
].
setValue
(
value
)
pref
.
asInstanceOf
[
ListPreference
].
setValue
(
value
)
...
@@ -172,10 +169,6 @@ object Shadowsocks {
...
@@ -172,10 +169,6 @@ object Shadowsocks {
}
}
}
}
def
isServiceStarted
(
context
:
Context
)
:
Boolean
=
{
ShadowsocksService
.
isServiceStarted
(
context
)
||
ShadowVpnService
.
isServiceStarted
(
context
)
}
class
ProxyFragment
extends
UnifiedPreferenceFragment
{
class
ProxyFragment
extends
UnifiedPreferenceFragment
{
var
receiver
:
BroadcastReceiver
=
null
var
receiver
:
BroadcastReceiver
=
null
...
@@ -194,8 +187,8 @@ object Shadowsocks {
...
@@ -194,8 +187,8 @@ object Shadowsocks {
private
def
updatePreferenceScreen
()
{
private
def
updatePreferenceScreen
()
{
for
(
name
<-
Shadowsocks
.
PROXY_PREFS
)
{
for
(
name
<-
Shadowsocks
.
PROXY_PREFS
)
{
val
pref
=
findPreference
(
name
)
val
pref
=
findPreference
(
name
)
Shadowsocks
.
updatePreference
(
pref
,
name
,
Shadowsocks
getActivity
.
asInstanceOf
[
Shadowsocks
].
currentProfile
)
.
updatePreference
(
pref
,
name
,
getActivity
.
asInstanceOf
[
Shadowsocks
].
currentProfile
)
}
}
}
}
...
@@ -252,8 +245,8 @@ object Shadowsocks {
...
@@ -252,8 +245,8 @@ object Shadowsocks {
private
def
updatePreferenceScreen
()
{
private
def
updatePreferenceScreen
()
{
for
(
name
<-
Shadowsocks
.
FEATRUE_PREFS
)
{
for
(
name
<-
Shadowsocks
.
FEATRUE_PREFS
)
{
val
pref
=
findPreference
(
name
)
val
pref
=
findPreference
(
name
)
Shadowsocks
.
updatePreference
(
pref
,
name
,
Shadowsocks
getActivity
.
asInstanceOf
[
Shadowsocks
].
currentProfile
)
.
updatePreference
(
pref
,
name
,
getActivity
.
asInstanceOf
[
Shadowsocks
].
currentProfile
)
}
}
}
}
...
@@ -304,9 +297,49 @@ class Shadowsocks
...
@@ -304,9 +297,49 @@ class Shadowsocks
var
prepared
=
false
var
prepared
=
false
var
currentProfile
=
new
Profile
var
currentProfile
=
new
Profile
// Services
var
currentServiceName
=
classOf
[
ShadowsocksNatService
].
getName
var
bgService
:
IShadowsocksService
=
null
val
callback
=
new
IShadowsocksServiceCallback
.
Stub
{
override
def
stateChanged
(
state
:
Int
,
msg
:
String
)
{
onStateChanged
(
state
,
msg
)
}
}
val
connection
=
new
ServiceConnection
{
override
def
onServiceConnected
(
name
:
ComponentName
,
service
:
IBinder
)
{
// Initialize the background service
bgService
=
IShadowsocksService
.
Stub
.
asInterface
(
service
)
try
{
bgService
.
registerCallback
(
callback
)
}
catch
{
case
ignored
:
RemoteException
=>
// Nothing
}
// Update the UI
switchButton
.
setEnabled
(
true
)
if
(
State
.
isAvailable
(
bgService
.
getState
))
{
if
(
status
.
getBoolean
(
Key
.
isRunning
,
false
))
{
spawn
{
crash_recovery
()
handler
.
sendEmptyMessage
(
MSG_CRASH_RECOVER
)
}
}
Crouton
.
cancelAllCroutons
()
setPreferenceEnabled
(
enabled
=
true
)
}
else
{
changeSwitch
(
checked
=
true
)
setPreferenceEnabled
(
enabled
=
false
)
}
state
=
bgService
.
getState
}
override
def
onServiceDisconnected
(
name
:
ComponentName
)
{
switchButton
.
setEnabled
(
false
)
bgService
=
null
}
}
lazy
val
settings
=
PreferenceManager
.
getDefaultSharedPreferences
(
this
)
lazy
val
settings
=
PreferenceManager
.
getDefaultSharedPreferences
(
this
)
lazy
val
status
=
getSharedPreferences
(
Key
.
status
,
Context
.
MODE_PRIVATE
)
lazy
val
status
=
getSharedPreferences
(
Key
.
status
,
Context
.
MODE_PRIVATE
)
lazy
val
stateReceiver
=
new
StateBroadcastReceiver
lazy
val
preferenceReceiver
=
new
PreferenceBroadcastReceiver
lazy
val
preferenceReceiver
=
new
PreferenceBroadcastReceiver
lazy
val
drawer
=
MenuDrawer
.
attach
(
this
)
lazy
val
drawer
=
MenuDrawer
.
attach
(
this
)
lazy
val
menuAdapter
=
new
MenuAdapter
(
this
,
getMenuList
)
lazy
val
menuAdapter
=
new
MenuAdapter
(
this
,
getMenuList
)
...
@@ -325,6 +358,18 @@ class Shadowsocks
...
@@ -325,6 +358,18 @@ class Shadowsocks
}
}
}
}
private
def
changeSwitch
(
checked
:
Boolean
)
{
switchButton
.
setOnCheckedChangeListener
(
null
)
switchButton
.
setChecked
(
checked
)
if
(
switchButton
.
isEnabled
)
{
switchButton
.
setEnabled
(
false
)
handler
.
postDelayed
(
new
Runnable
{
override
def
run
()
{
switchButton
.
setEnabled
(
true
)
}
},
1000
)
}
switchButton
.
setOnCheckedChangeListener
(
this
)
}
private
def
showProgress
(
msg
:
String
)
:
Handler
=
{
private
def
showProgress
(
msg
:
String
)
:
Handler
=
{
clearDialog
()
clearDialog
()
progressDialog
=
ProgressDialog
.
show
(
this
,
""
,
msg
,
true
,
false
)
progressDialog
=
ProgressDialog
.
show
(
this
,
""
,
msg
,
true
,
false
)
...
@@ -341,10 +386,9 @@ class Shadowsocks
...
@@ -341,10 +386,9 @@ class Shadowsocks
try
{
try
{
files
=
assetManager
.
list
(
path
)
files
=
assetManager
.
list
(
path
)
}
catch
{
}
catch
{
case
e
:
IOException
=>
{
case
e
:
IOException
=>
Log
.
e
(
Shadowsocks
.
TAG
,
e
.
getMessage
)
Log
.
e
(
Shadowsocks
.
TAG
,
e
.
getMessage
)
}
}
}
if
(
files
!=
null
)
{
if
(
files
!=
null
)
{
for
(
file
<-
files
)
{
for
(
file
<-
files
)
{
var
in
:
InputStream
=
null
var
in
:
InputStream
=
null
...
@@ -363,13 +407,12 @@ class Shadowsocks
...
@@ -363,13 +407,12 @@ class Shadowsocks
out
.
close
()
out
.
close
()
out
=
null
out
=
null
}
catch
{
}
catch
{
case
ex
:
Exception
=>
{
case
ex
:
Exception
=>
Log
.
e
(
Shadowsocks
.
TAG
,
ex
.
getMessage
)
Log
.
e
(
Shadowsocks
.
TAG
,
ex
.
getMessage
)
}
}
}
}
}
}
}
}
}
private
def
copyFile
(
in
:
InputStream
,
out
:
OutputStream
)
{
private
def
copyFile
(
in
:
InputStream
,
out
:
OutputStream
)
{
val
buffer
:
Array
[
Byte
]
=
new
Array
[
Byte
](
1024
)
val
buffer
:
Array
[
Byte
]
=
new
Array
[
Byte
](
1024
)
...
@@ -409,21 +452,29 @@ class Shadowsocks
...
@@ -409,21 +452,29 @@ class Shadowsocks
val
pi
:
PackageInfo
=
getPackageManager
.
getPackageInfo
(
getPackageName
,
0
)
val
pi
:
PackageInfo
=
getPackageManager
.
getPackageInfo
(
getPackageName
,
0
)
version
=
pi
.
versionName
version
=
pi
.
versionName
}
catch
{
}
catch
{
case
e
:
PackageManager.NameNotFoundException
=>
{
case
e
:
PackageManager.NameNotFoundException
=>
version
=
"Package name not found"
version
=
"Package name not found"
}
}
}
version
version
}
}
private
def
isTextEmpty
(
s
:
String
,
msg
:
String
)
:
Boolean
=
{
def
isTextEmpty
(
s
:
String
,
msg
:
String
)
:
Boolean
=
{
if
(
s
==
null
||
s
.
length
<=
0
)
{
if
(
s
==
null
||
s
.
length
<=
0
)
{
showDialog
(
msg
)
Crouton
.
makeText
(
this
,
msg
,
Style
.
ALERT
).
show
(
)
return
true
return
true
}
}
false
false
}
}
def
cancelStart
()
{
handler
.
postDelayed
(
new
Runnable
{
override
def
run
()
{
clearDialog
()
changeSwitch
(
checked
=
false
)
}
},
1000
)
}
def
prepareStartService
()
{
def
prepareStartService
()
{
showProgress
(
getString
(
R
.
string
.
connecting
))
showProgress
(
getString
(
R
.
string
.
connecting
))
spawn
{
spawn
{
...
@@ -436,7 +487,7 @@ class Shadowsocks
...
@@ -436,7 +487,7 @@ class Shadowsocks
}
}
}
else
{
}
else
{
if
(!
serviceStart
)
{
if
(!
serviceStart
)
{
switchButton
.
setChecked
(
false
)
cancelStart
(
)
}
}
}
}
}
}
...
@@ -445,12 +496,16 @@ class Shadowsocks
...
@@ -445,12 +496,16 @@ class Shadowsocks
def
onCheckedChanged
(
compoundButton
:
CompoundButton
,
checked
:
Boolean
)
{
def
onCheckedChanged
(
compoundButton
:
CompoundButton
,
checked
:
Boolean
)
{
if
(
compoundButton
eq
switchButton
)
{
if
(
compoundButton
eq
switchButton
)
{
checked
match
{
checked
match
{
case
true
=>
{
case
true
=>
prepareStartService
()
prepareStartService
()
}
case
false
=>
case
false
=>
{
serviceStop
()
serviceStop
()
}
}
if
(
switchButton
.
isEnabled
)
{
switchButton
.
setEnabled
(
false
)
handler
.
postDelayed
(
new
Runnable
{
override
def
run
()
{
switchButton
.
setEnabled
(
true
)
}
},
1000
)
}
}
}
}
}
}
...
@@ -491,18 +546,28 @@ class Shadowsocks
...
@@ -491,18 +546,28 @@ class Shadowsocks
onContentChanged
()
onContentChanged
()
}
}
/** Called when the activity is first created. */
override
def
onCreate
(
savedInstanceState
:
Bundle
)
{
override
def
onCreate
(
savedInstanceState
:
Bundle
)
{
// Initialize preference
// Initialize
the
preference
setHeaderRes
(
R
.
xml
.
shadowsocks_headers
)
setHeaderRes
(
R
.
xml
.
shadowsocks_headers
)
super
.
onCreate
(
savedInstanceState
)
super
.
onCreate
(
savedInstanceState
)
// Initialize profile
// Initialize
the
profile
currentProfile
=
{
currentProfile
=
{
profileManager
.
getProfile
(
settings
.
getInt
(
Key
.
profileId
,
-
1
))
getOrElse
currentProfile
profileManager
.
getProfile
(
settings
.
getInt
(
Key
.
profileId
,
-
1
))
getOrElse
currentProfile
}
}
// Update the profile
if
(!
status
.
getBoolean
(
getVersionName
,
false
))
{
val
h
=
showProgress
(
getString
(
R
.
string
.
initializing
))
status
.
edit
.
putBoolean
(
getVersionName
,
true
).
apply
()
spawn
{
reset
()
currentProfile
=
profileManager
.
create
()
h
.
sendEmptyMessage
(
0
)
}
}
// Initialize drawer
// Initialize drawer
menuAdapter
.
setActiveId
(
settings
.
getInt
(
Key
.
profileId
,
-
1
))
menuAdapter
.
setActiveId
(
settings
.
getInt
(
Key
.
profileId
,
-
1
))
menuAdapter
.
setListener
(
this
)
menuAdapter
.
setListener
(
this
)
...
@@ -527,23 +592,34 @@ class Shadowsocks
...
@@ -527,23 +592,34 @@ class Shadowsocks
getSupportActionBar
.
setIcon
(
R
.
drawable
.
ic_stat_shadowsocks
)
getSupportActionBar
.
setIcon
(
R
.
drawable
.
ic_stat_shadowsocks
)
// Register broadcast receiver
// Register broadcast receiver
registerReceiver
(
stateReceiver
,
new
IntentFilter
(
Action
.
UPDATE_STATE
))
registerReceiver
(
preferenceReceiver
,
new
IntentFilter
(
Action
.
UPDATE_PREFS
))
registerReceiver
(
preferenceReceiver
,
new
IntentFilter
(
Action
.
UPDATE_PREFS
))
// Update status
// Bind to the service
if
(!
Shadowsocks
.
isServiceStarted
(
this
))
{
spawn
{
spawn
{
status
.
edit
.
putBoolean
(
Key
.
isRoot
,
Utils
.
getRoot
).
apply
()
val
isRoot
=
Utils
.
getRoot
handler
.
post
(
new
Runnable
{
override
def
run
()
{
status
.
edit
.
putBoolean
(
Key
.
isRoot
,
isRoot
).
commit
()
attachService
()
}
}
if
(!
status
.
getBoolean
(
getVersionName
,
false
))
{
})
val
h
=
showProgress
(
getString
(
R
.
string
.
initializing
))
status
.
edit
.
putBoolean
(
getVersionName
,
true
).
apply
()
spawn
{
reset
()
currentProfile
=
profileManager
.
create
()
h
.
sendEmptyMessage
(
0
)
}
}
}
}
def
attachService
()
{
if
(
bgService
==
null
)
{
val
isRoot
=
status
.
getBoolean
(
Key
.
isRoot
,
false
)
val
s
=
if
(
isRoot
)
classOf
[
ShadowsocksNatService
]
else
classOf
[
ShadowsocksVpnService
]
bindService
(
new
Intent
(
s
.
getName
),
connection
,
Context
.
BIND_AUTO_CREATE
)
startService
(
new
Intent
(
Shadowsocks
.
this
,
s
))
}
}
def
deattachService
()
{
if
(
bgService
!=
null
)
{
bgService
.
unregisterCallback
(
callback
)
unbindService
(
connection
)
bgService
=
null
}
}
}
}
...
@@ -571,15 +647,15 @@ class Shadowsocks
...
@@ -571,15 +647,15 @@ class Shadowsocks
drawer
.
setActiveView
(
v
,
pos
)
drawer
.
setActiveView
(
v
,
pos
)
}
}
def
newProfile
(
id
:
Int
)
{
def
newProfile
(
id
:
Int
)
{
val
builder
=
new
AlertDialog
.
Builder
(
this
)
val
builder
=
new
AlertDialog
.
Builder
(
this
)
builder
.
setTitle
(
R
.
string
.
add_profile
)
builder
.
setTitle
(
R
.
string
.
add_profile
)
.
setItems
(
R
.
array
.
add_profile_methods
,
new
DialogInterface
.
OnClickListener
()
{
.
setItems
(
R
.
array
.
add_profile_methods
,
new
DialogInterface
.
OnClickListener
()
{
def
onClick
(
dialog
:
DialogInterface
,
which
:
Int
)
{
def
onClick
(
dialog
:
DialogInterface
,
which
:
Int
)
{
which
match
{
which
match
{
case
0
=>
{
case
0
=>
dialog
.
dismiss
()
dialog
.
dismiss
()
val
h
=
showProgress
(
getString
(
R
.
string
.
loading
))
val
h
=
showProgress
(
getString
(
R
.
string
.
loading
))
h
.
postDelayed
(
new
Runnable
()
{
h
.
postDelayed
(
new
Runnable
()
{
...
@@ -589,17 +665,14 @@ class Shadowsocks
...
@@ -589,17 +665,14 @@ class Shadowsocks
h
.
sendEmptyMessage
(
0
)
h
.
sendEmptyMessage
(
0
)
}
}
},
600
)
},
600
)
}
case
1
=>
case
1
=>
{
dialog
.
dismiss
()
dialog
.
dismiss
()
addProfile
(
id
)
addProfile
(
id
)
}
case
_
=>
case
_
=>
}
}
}
}
})
})
builder
.
create
().
show
()
builder
.
create
().
show
()
}
}
def
addProfile
(
profile
:
Profile
)
{
def
addProfile
(
profile
:
Profile
)
{
...
@@ -753,53 +826,35 @@ class Shadowsocks
...
@@ -753,53 +826,35 @@ class Shadowsocks
override
def
onOptionsItemSelected
(
item
:
com.actionbarsherlock.view.MenuItem
)
:
Boolean
=
{
override
def
onOptionsItemSelected
(
item
:
com.actionbarsherlock.view.MenuItem
)
:
Boolean
=
{
item
.
getItemId
match
{
item
.
getItemId
match
{
case
android
.
R
.
id
.
home
=>
{
case
android
.
R
.
id
.
home
=>
drawer
.
toggleMenu
()
drawer
.
toggleMenu
()
return
true
return
true
}
}
}
super
.
onOptionsItemSelected
(
item
)
super
.
onOptionsItemSelected
(
item
)
}
}
protected
override
def
onPause
()
{
protected
override
def
onPause
()
{
super
.
onPause
()
super
.
onPause
()
switchButton
.
setOnCheckedChangeListener
(
null
)
prepared
=
false
prepared
=
false
}
}
protected
override
def
onResume
()
{
protected
override
def
onResume
()
{
super
.
onResume
()
super
.
onResume
()
if
(!
prepared
)
{
if
(
bgService
!=
null
)
{
if
(
Shadowsocks
.
isServiceStarted
(
this
))
{
bgService
.
getState
match
{
switchButton
.
setChecked
(
true
)
case
State
.
CONNECTED
=>
if
(
ShadowVpnService
.
isServiceStarted
(
this
))
{
changeSwitch
(
checked
=
true
)
val
style
=
new
Style
.
Builder
().
setBackgroundColorValue
(
Style
.
holoBlueLight
).
build
()
case
State
.
CONNECTING
=>
val
config
=
new
Configuration
.
Builder
().
setDuration
(
Configuration
.
DURATION_LONG
).
build
()
changeSwitch
(
checked
=
true
)
switchButton
.
setEnabled
(
false
)
case
_
=>
Crouton
changeSwitch
(
checked
=
false
)
.
makeText
(
Shadowsocks
.
this
,
R
.
string
.
vpn_status
,
style
)
.
setConfiguration
(
config
)
.
show
()
}
setPreferenceEnabled
(
enabled
=
false
)
onStateChanged
(
State
.
CONNECTED
,
null
)
}
else
{
switchButton
.
setEnabled
(
true
)
switchButton
.
setChecked
(
false
)
Crouton
.
cancelAllCroutons
()
setPreferenceEnabled
(
enabled
=
true
)
if
(
status
.
getBoolean
(
Key
.
isRunning
,
false
))
{
spawn
{
crash_recovery
()
handler
.
sendEmptyMessage
(
MSG_CRASH_RECOVER
)
}
}
onStateChanged
(
State
.
STOPPED
,
null
)
}
}
state
=
bgService
.
getState
}
}
// set the listener
switchButton
.
setOnCheckedChangeListener
(
this
)
switchButton
.
setOnCheckedChangeListener
(
Shadowsocks
.
this
)
ConfigUtils
.
refresh
(
this
)
Config
.
refresh
(
this
)
}
}
private
def
setPreferenceEnabled
(
enabled
:
Boolean
)
{
private
def
setPreferenceEnabled
(
enabled
:
Boolean
)
{
...
@@ -848,8 +903,8 @@ class Shadowsocks
...
@@ -848,8 +903,8 @@ class Shadowsocks
override
def
onDestroy
()
{
override
def
onDestroy
()
{
super
.
onDestroy
()
super
.
onDestroy
()
deattachService
()
Crouton
.
cancelAllCroutons
()
Crouton
.
cancelAllCroutons
()
unregisterReceiver
(
stateReceiver
)
unregisterReceiver
(
preferenceReceiver
)
unregisterReceiver
(
preferenceReceiver
)
new
BackupManager
(
this
).
dataChanged
()
new
BackupManager
(
this
).
dataChanged
()
}
}
...
@@ -866,7 +921,6 @@ class Shadowsocks
...
@@ -866,7 +921,6 @@ class Shadowsocks
private
def
recovery
()
{
private
def
recovery
()
{
val
h
=
showProgress
(
getString
(
R
.
string
.
recovering
))
val
h
=
showProgress
(
getString
(
R
.
string
.
recovering
))
serviceStop
()
serviceStop
()
spawn
{
spawn
{
reset
()
reset
()
...
@@ -891,24 +945,22 @@ class Shadowsocks
...
@@ -891,24 +945,22 @@ class Shadowsocks
}
}
}
else
{
}
else
{
resultCode
match
{
resultCode
match
{
case
Activity
.
RESULT_OK
=>
{
case
Activity
.
RESULT_OK
=>
prepared
=
true
prepared
=
true
if
(!
serviceStart
)
{
if
(!
serviceStart
)
{
switchButton
.
setChecked
(
false
)
cancelStart
(
)
}
}
}
case
_
=>
case
_
=>
{
cancelStart
()
clearDialog
()
Log
.
e
(
Shadowsocks
.
TAG
,
"Failed to start VpnService"
)
Log
.
e
(
Shadowsocks
.
TAG
,
"Failed to start VpnService"
)
}
}
}
}
}
}
}
def
isVpnEnabled
:
Boolean
=
{
def
isVpnEnabled
:
Boolean
=
{
if
(
Shadowsocks
.
vpnEnabled
<
0
)
{
if
(
Shadowsocks
.
vpnEnabled
<
0
)
{
Shadowsocks
.
vpnEnabled
=
if
(
Build
.
VERSION
.
SDK_INT
Shadowsocks
.
vpnEnabled
=
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
ICE_CREAM_SANDWICH
&&
!
Utils
.
getRoot
)
{
>=
Build
.
VERSION_CODES
.
ICE_CREAM_SANDWICH
&&
!
status
.
getBoolean
(
Key
.
isRoot
,
false
)
)
{
1
1
}
else
{
}
else
{
0
0
...
@@ -918,43 +970,48 @@ class Shadowsocks
...
@@ -918,43 +970,48 @@ class Shadowsocks
}
}
def
serviceStop
()
{
def
serviceStop
()
{
sendBroadcast
(
new
Intent
(
Action
.
CLOSE
)
)
if
(
bgService
!=
null
)
bgService
.
stop
(
)
}
}
/** Called when connect button is clicked. */
def
checkText
(
key
:
String
)
:
Boolean
=
{
def
serviceStart
:
Boolean
=
{
val
text
=
settings
.
getString
(
key
,
""
)
!
isTextEmpty
(
text
,
getString
(
R
.
string
.
proxy_empty
))
}
val
proxy
=
settings
.
getString
(
Key
.
proxy
,
""
)
def
checkNumber
(
key
:
String
)
:
Boolean
=
{
if
(
isTextEmpty
(
proxy
,
getString
(
R
.
string
.
proxy_empty
)))
return
false
val
text
=
settings
.
getString
(
key
,
""
)
val
portText
=
settings
.
getString
(
Key
.
localPort
,
""
)
if
(
isTextEmpty
(
text
,
getString
(
R
.
string
.
port_empty
)))
return
false
if
(
isTextEmpty
(
portText
,
getString
(
R
.
string
.
port_empty
)))
return
false
try
{
try
{
val
port
:
Int
=
Integer
.
valueOf
(
portT
ext
)
val
port
:
Int
=
Integer
.
valueOf
(
t
ext
)
if
(
port
<=
1024
)
{
if
(
port
<=
1024
)
{
this
.
showDialog
(
getString
(
R
.
string
.
port_alert
)
)
Crouton
.
makeText
(
this
,
R
.
string
.
port_alert
,
Style
.
ALERT
).
show
(
)
return
false
return
false
}
}
}
catch
{
}
catch
{
case
ex
:
Exception
=>
{
case
ex
:
Exception
=>
this
.
showDialog
(
getString
(
R
.
string
.
port_alert
)
)
Crouton
.
makeText
(
this
,
R
.
string
.
port_alert
,
Style
.
ALERT
).
show
(
)
return
false
return
false
}
}
true
}
}
/** Called when connect button is clicked. */
def
serviceStart
:
Boolean
=
{
if
(!
checkText
(
Key
.
proxy
))
return
false
if
(!
checkText
(
Key
.
sitekey
))
return
false
if
(!
checkNumber
(
Key
.
localPort
))
return
false
if
(!
checkNumber
(
Key
.
remotePort
))
return
false
if
(
bgService
==
null
)
return
false
bgService
.
start
(
ConfigUtils
.
load
(
settings
))
if
(
isVpnEnabled
)
{
if
(
isVpnEnabled
)
{
if
(
ShadowVpnService
.
isServiceStarted
(
this
))
return
false
val
intent
:
Intent
=
new
Intent
(
this
,
classOf
[
ShadowVpnService
])
Extra
.
put
(
settings
,
intent
)
startService
(
intent
)
val
style
=
new
Style
.
Builder
().
setBackgroundColorValue
(
Style
.
holoBlueLight
).
build
()
val
style
=
new
Style
.
Builder
().
setBackgroundColorValue
(
Style
.
holoBlueLight
).
build
()
val
config
=
new
Configuration
.
Builder
().
setDuration
(
Configuration
.
DURATION_LONG
).
build
()
val
config
=
new
Configuration
.
Builder
().
setDuration
(
Configuration
.
DURATION_LONG
).
build
()
Crouton
.
makeText
(
Shadowsocks
.
this
,
R
.
string
.
vpn_status
,
style
).
setConfiguration
(
config
).
show
()
Crouton
.
makeText
(
Shadowsocks
.
this
,
R
.
string
.
vpn_status
,
style
).
setConfiguration
(
config
).
show
()
switchButton
.
setEnabled
(
false
)
changeSwitch
(
checked
=
false
)
}
else
{
if
(
ShadowsocksService
.
isServiceStarted
(
this
))
return
false
val
intent
:
Intent
=
new
Intent
(
this
,
classOf
[
ShadowsocksService
])
Extra
.
put
(
settings
,
intent
)
startService
(
intent
)
}
}
true
true
}
}
...
@@ -974,10 +1031,9 @@ class Shadowsocks
...
@@ -974,10 +1031,9 @@ class Shadowsocks
try
{
try
{
versionName
=
getPackageManager
.
getPackageInfo
(
getPackageName
,
0
).
versionName
versionName
=
getPackageManager
.
getPackageInfo
(
getPackageName
,
0
).
versionName
}
catch
{
}
catch
{
case
ex
:
PackageManager.NameNotFoundException
=>
{
case
ex
:
PackageManager.NameNotFoundException
=>
versionName
=
""
versionName
=
""
}
}
}
new
AlertDialog
.
Builder
(
this
)
new
AlertDialog
.
Builder
(
this
)
.
setTitle
(
getString
(
R
.
string
.
about_title
).
format
(
versionName
))
.
setTitle
(
getString
(
R
.
string
.
about_title
).
format
(
versionName
))
...
@@ -992,20 +1048,6 @@ class Shadowsocks
...
@@ -992,20 +1048,6 @@ class Shadowsocks
.
show
()
.
show
()
}
}
private
def
showDialog
(
msg
:
String
)
{
val
builder
:
AlertDialog.Builder
=
new
AlertDialog
.
Builder
(
this
)
builder
.
setMessage
(
msg
)
.
setCancelable
(
false
)
.
setNegativeButton
(
getString
(
R
.
string
.
ok_iknow
),
new
DialogInterface
.
OnClickListener
{
def
onClick
(
dialog
:
DialogInterface
,
id
:
Int
)
{
dialog
.
cancel
()
}
})
val
alert
:
AlertDialog
=
builder
.
create
alert
.
show
()
}
def
clearDialog
()
{
def
clearDialog
()
{
if
(
progressDialog
!=
null
)
{
if
(
progressDialog
!=
null
)
{
progressDialog
.
dismiss
()
progressDialog
.
dismiss
()
...
@@ -1014,28 +1056,25 @@ class Shadowsocks
...
@@ -1014,28 +1056,25 @@ class Shadowsocks
}
}
def
onStateChanged
(
s
:
Int
,
m
:
String
)
{
def
onStateChanged
(
s
:
Int
,
m
:
String
)
{
handler
.
post
(
new
Runnable
{
override
def
run
()
{
if
(
state
!=
s
)
{
if
(
state
!=
s
)
{
state
=
s
state
=
s
state
match
{
state
match
{
case
State
.
CONNECTING
=>
{
case
State
.
CONNECTING
=>
if
(
progressDialog
==
null
)
{
if
(
progressDialog
==
null
)
{
progressDialog
=
ProgressDialog
progressDialog
=
ProgressDialog
.
show
(
Shadowsocks
.
this
,
""
,
getString
(
R
.
string
.
connecting
),
true
,
true
)
.
show
(
Shadowsocks
.
this
,
""
,
getString
(
R
.
string
.
connecting
),
true
,
true
)
}
}
setPreferenceEnabled
(
enabled
=
false
)
setPreferenceEnabled
(
enabled
=
false
)
}
case
State
.
CONNECTED
=>
case
State
.
CONNECTED
=>
{
clearDialog
()
clearDialog
()
if
(!
switchButton
.
isChecked
)
switchButton
.
setChecked
(
true
)
changeSwitch
(
checked
=
true
)
setPreferenceEnabled
(
enabled
=
false
)
setPreferenceEnabled
(
enabled
=
false
)
}
case
State
.
STOPPED
=>
case
State
.
STOPPED
=>
{
clearDialog
()
clearDialog
()
if
(
switchButton
.
isChecked
)
{
changeSwitch
(
checked
=
false
)
switchButton
.
setEnabled
(
true
)
switchButton
.
setChecked
(
false
)
Crouton
.
cancelAllCroutons
()
Crouton
.
cancelAllCroutons
()
}
if
(
m
!=
null
)
{
if
(
m
!=
null
)
{
Crouton
.
cancelAllCroutons
()
Crouton
.
cancelAllCroutons
()
val
style
=
new
Style
.
Builder
().
setBackgroundColorValue
(
Style
.
holoRedLight
).
build
()
val
style
=
new
Style
.
Builder
().
setBackgroundColorValue
(
Style
.
holoRedLight
).
build
()
...
@@ -1049,10 +1088,11 @@ class Shadowsocks
...
@@ -1049,10 +1088,11 @@ class Shadowsocks
}
}
setPreferenceEnabled
(
enabled
=
true
)
setPreferenceEnabled
(
enabled
=
true
)
}
}
}
if
(!
isSinglePane
)
sendBroadcast
(
new
Intent
(
Action
.
UPDATE_FRAGMENT
))
if
(!
isSinglePane
)
sendBroadcast
(
new
Intent
(
Action
.
UPDATE_FRAGMENT
))
}
}
}
}
})
}
class
PreferenceBroadcastReceiver
extends
BroadcastReceiver
{
class
PreferenceBroadcastReceiver
extends
BroadcastReceiver
{
override
def
onReceive
(
context
:
Context
,
intent
:
Intent
)
{
override
def
onReceive
(
context
:
Context
,
intent
:
Intent
)
{
...
@@ -1061,12 +1101,4 @@ class Shadowsocks
...
@@ -1061,12 +1101,4 @@ class Shadowsocks
}
}
}
}
class
StateBroadcastReceiver
extends
BroadcastReceiver
{
override
def
onReceive
(
context
:
Context
,
intent
:
Intent
)
{
val
state
=
intent
.
getIntExtra
(
Extra
.
STATE
,
State
.
INIT
)
val
message
=
intent
.
getStringExtra
(
Extra
.
MESSAGE
)
onStateChanged
(
state
,
message
)
}
}
}
}
src/main/scala/com/github/shadowsocks/ShadowsocksService.scala
→
src/main/scala/com/github/shadowsocks/Shadowsocks
Nat
Service.scala
View file @
0b8114ad
...
@@ -61,18 +61,13 @@ import scala.concurrent.ops._
...
@@ -61,18 +61,13 @@ import scala.concurrent.ops._
import
com.github.shadowsocks.utils._
import
com.github.shadowsocks.utils._
import
scala.Some
import
scala.Some
import
android.graphics.Color
import
android.graphics.Color
import
com.github.shadowsocks.aidl.Config
case
class
TrafficStat
(
tx
:
Long
,
rx
:
Long
,
timestamp
:
Long
)
case
class
TrafficStat
(
tx
:
Long
,
rx
:
Long
,
timestamp
:
Long
)
object
ShadowsocksService
{
class
ShadowsocksNatService
extends
Service
with
BaseService
{
def
isServiceStarted
(
context
:
Context
)
:
Boolean
=
{
Utils
.
isServiceStarted
(
"com.github.shadowsocks.ShadowsocksService"
,
context
)
}
}
class
ShadowsocksService
extends
Service
{
val
TAG
=
"ShadowsocksNatService"
val
TAG
=
"ShadowsocksService"
val
CMD_IPTABLES_RETURN
=
" -t nat -A OUTPUT -p tcp -d 0.0.0.0 -j RETURN\n"
val
CMD_IPTABLES_RETURN
=
" -t nat -A OUTPUT -p tcp -d 0.0.0.0 -j RETURN\n"
val
CMD_IPTABLES_REDIRECT_ADD_SOCKS
=
" -t nat -A OUTPUT -p tcp "
+
"-j REDIRECT --to 8123\n"
val
CMD_IPTABLES_REDIRECT_ADD_SOCKS
=
" -t nat -A OUTPUT -p tcp "
+
"-j REDIRECT --to 8123\n"
...
@@ -80,12 +75,6 @@ class ShadowsocksService extends Service {
...
@@ -80,12 +75,6 @@ class ShadowsocksService extends Service {
"-j DNAT --to-destination 127.0.0.1:8123\n"
"-j DNAT --to-destination 127.0.0.1:8123\n"
val
DNS_PORT
=
8153
val
DNS_PORT
=
8153
val
MSG_CONNECT_FINISH
=
1
val
MSG_CONNECT_SUCCESS
=
2
val
MSG_CONNECT_FAIL
=
3
val
MSG_STOP_SELF
=
4
val
MSG_VPN_ERROR
=
5
private
val
mStartForegroundSignature
=
Array
[
Class
[
_
]](
classOf
[
Int
],
classOf
[
Notification
])
private
val
mStartForegroundSignature
=
Array
[
Class
[
_
]](
classOf
[
Int
],
classOf
[
Notification
])
private
val
mStopForegroundSignature
=
Array
[
Class
[
_
]](
classOf
[
Boolean
])
private
val
mStopForegroundSignature
=
Array
[
Class
[
_
]](
classOf
[
Boolean
])
private
val
mSetForegroundSignature
=
Array
[
Class
[
_
]](
classOf
[
Boolean
])
private
val
mSetForegroundSignature
=
Array
[
Class
[
_
]](
classOf
[
Boolean
])
...
@@ -104,56 +93,25 @@ class ShadowsocksService extends Service {
...
@@ -104,56 +93,25 @@ class ShadowsocksService extends Service {
private
var
mStartForegroundArgs
=
new
Array
[
AnyRef
](
2
)
private
var
mStartForegroundArgs
=
new
Array
[
AnyRef
](
2
)
private
var
mStopForegroundArgs
=
new
Array
[
AnyRef
](
1
)
private
var
mStopForegroundArgs
=
new
Array
[
AnyRef
](
1
)
private
var
state
=
State
.
INIT
private
var
last
:
TrafficStat
=
null
private
var
last
:
TrafficStat
=
null
private
var
lastTxRate
=
0
private
var
lastTxRate
=
0
private
var
lastRxRate
=
0
private
var
lastRxRate
=
0
private
var
timer
:
Timer
=
null
private
var
timer
:
Timer
=
null
private
val
TIMER_INTERVAL
=
2
private
val
TIMER_INTERVAL
=
2
private
def
changeState
(
s
:
Int
)
{
if
(
state
!=
s
)
{
state
=
s
val
intent
=
new
Intent
(
Action
.
UPDATE_STATE
)
intent
.
putExtra
(
Extra
.
STATE
,
state
)
sendBroadcast
(
intent
)
}
}
val
handler
:
Handler
=
new
Handler
{
val
handler
:
Handler
=
new
Handler
{
override
def
handleMessage
(
msg
:
Message
)
{
override
def
handleMessage
(
msg
:
Message
)
{
msg
.
what
match
{
msg
.
what
match
{
case
M
SG_
CONNECT_SUCCESS
=>
case
M
sg
.
CONNECT_SUCCESS
=>
changeState
(
State
.
CONNECTED
)
changeState
(
State
.
CONNECTED
)
case
M
SG_
CONNECT_FAIL
=>
case
M
sg
.
CONNECT_FAIL
=>
changeState
(
State
.
STOPPED
)
changeState
(
State
.
STOPPED
)
case
MSG_STOP_SELF
=>
stopSelf
()
case
_
=>
case
_
=>
}
}
super
.
handleMessage
(
msg
)
super
.
handleMessage
(
msg
)
}
}
}
}
def
getPid
(
name
:
String
)
:
Int
=
{
try
{
val
reader
:
BufferedReader
=
new
BufferedReader
(
new
FileReader
(
Path
.
BASE
+
name
+
".pid"
))
val
line
=
reader
.
readLine
return
Integer
.
valueOf
(
line
)
}
catch
{
case
e
:
FileNotFoundException
=>
{
Log
.
e
(
TAG
,
"Cannot open pid file: "
+
name
)
}
case
e
:
IOException
=>
{
Log
.
e
(
TAG
,
"Cannot read pid file: "
+
name
)
}
case
e
:
NumberFormatException
=>
{
Log
.
e
(
TAG
,
"Invalid pid"
,
e
)
}
}
-
1
}
def
startShadowsocksDaemon
()
{
def
startShadowsocksDaemon
()
{
val
cmd
:
String
=
(
Path
.
BASE
+
val
cmd
:
String
=
(
Path
.
BASE
+
"shadowsocks -b 127.0.0.1 -s \"%s\" -p \"%d\" -l \"%d\" -k \"%s\" -m \"%s\" -f "
+
"shadowsocks -b 127.0.0.1 -s \"%s\" -p \"%d\" -l \"%d\" -k \"%s\" -m \"%s\" -f "
+
...
@@ -165,8 +123,8 @@ class ShadowsocksService extends Service {
...
@@ -165,8 +123,8 @@ class ShadowsocksService extends Service {
def
startDnsDaemon
()
{
def
startDnsDaemon
()
{
val
cmd
:
String
=
Path
.
BASE
+
"pdnsd -c "
+
Path
.
BASE
+
"pdnsd.conf"
val
cmd
:
String
=
Path
.
BASE
+
"pdnsd -c "
+
Path
.
BASE
+
"pdnsd.conf"
val
conf
:
String
=
Config
.
PDNSD
.
format
(
"127.0.0.1"
)
val
conf
:
String
=
Config
Utils
.
PDNSD
.
format
(
"127.0.0.1"
)
Config
.
printToFile
(
new
File
(
Path
.
BASE
+
"pdnsd.conf"
))(
p
=>
{
Config
Utils
.
printToFile
(
new
File
(
Path
.
BASE
+
"pdnsd.conf"
))(
p
=>
{
p
.
println
(
conf
)
p
.
println
(
conf
)
})
})
Utils
.
runCommand
(
cmd
)
Utils
.
runCommand
(
cmd
)
...
@@ -178,101 +136,17 @@ class ShadowsocksService extends Service {
...
@@ -178,101 +136,17 @@ class ShadowsocksService extends Service {
val
pi
:
PackageInfo
=
getPackageManager
.
getPackageInfo
(
getPackageName
,
0
)
val
pi
:
PackageInfo
=
getPackageManager
.
getPackageInfo
(
getPackageName
,
0
)
version
=
pi
.
versionName
version
=
pi
.
versionName
}
catch
{
}
catch
{
case
e
:
PackageManager.NameNotFoundException
=>
{
case
e
:
PackageManager.NameNotFoundException
=>
version
=
"Package name not found"
version
=
"Package name not found"
}
}
}
version
version
}
}
def
handleCommand
(
intent
:
Intent
)
{
if
(
intent
==
null
)
{
stopSelf
()
return
}
changeState
(
State
.
CONNECTING
)
config
=
Extra
.
get
(
intent
)
if
(
config
.
isTrafficStat
)
{
// initialize timer
val
task
=
new
TimerTask
{
def
run
()
{
val
pm
=
getSystemService
(
Context
.
POWER_SERVICE
).
asInstanceOf
[
PowerManager
]
val
now
=
new
TrafficStat
(
TrafficStats
.
getUidTxBytes
(
uid
),
TrafficStats
.
getUidRxBytes
(
uid
),
java
.
lang
.
System
.
currentTimeMillis
())
val
txRate
=
((
now
.
tx
-
last
.
tx
)
/
1024
/
TIMER_INTERVAL
).
toInt
val
rxRate
=
((
now
.
rx
-
last
.
rx
)
/
1024
/
TIMER_INTERVAL
).
toInt
last
=
now
if
(
lastTxRate
==
txRate
&&
lastRxRate
==
rxRate
)
{
return
}
else
{
lastTxRate
=
txRate
lastRxRate
=
rxRate
}
if
((
pm
.
isScreenOn
&&
state
==
State
.
CONNECTED
)
||
(
txRate
==
0
&&
rxRate
==
0
))
{
notifyForegroundAlert
(
getString
(
R
.
string
.
forward_success
),
getString
(
R
.
string
.
service_status
).
format
(
math
.
max
(
txRate
,
rxRate
)),
math
.
max
(
txRate
,
rxRate
))
}
}
}
last
=
new
TrafficStat
(
TrafficStats
.
getUidTxBytes
(
uid
),
TrafficStats
.
getUidRxBytes
(
uid
),
java
.
lang
.
System
.
currentTimeMillis
())
timer
=
new
Timer
(
true
)
timer
.
schedule
(
task
,
TIMER_INTERVAL
*
1000
,
TIMER_INTERVAL
*
1000
)
}
spawn
{
if
(
config
.
proxy
==
"198.199.101.152"
)
{
val
container
=
getApplication
.
asInstanceOf
[
ShadowsocksApplication
].
tagContainer
try
{
config
=
Config
.
getPublicConfig
(
getBaseContext
,
container
,
config
)
}
catch
{
case
ex
:
Exception
=>
{
notifyAlert
(
getString
(
R
.
string
.
forward_fail
),
getString
(
R
.
string
.
service_failed
))
stopSelf
()
handler
.
sendEmptyMessageDelayed
(
MSG_CONNECT_FAIL
,
500
)
return
}
}
}
killProcesses
()
var
resolved
:
Boolean
=
false
if
(!
InetAddressUtils
.
isIPv4Address
(
config
.
proxy
)
&&
!
InetAddressUtils
.
isIPv6Address
(
config
.
proxy
))
{
Utils
.
resolve
(
config
.
proxy
,
enableIPv6
=
true
)
match
{
case
Some
(
a
)
=>
config
.
proxy
=
a
resolved
=
true
case
None
=>
resolved
=
false
}
}
else
{
resolved
=
true
}
hasRedirectSupport
=
Utils
.
getHasRedirectSupport
if
(
resolved
&&
handleConnection
)
{
notifyForegroundAlert
(
getString
(
R
.
string
.
forward_success
),
getString
(
R
.
string
.
service_running
).
format
(
config
.
profileName
))
handler
.
sendEmptyMessageDelayed
(
MSG_CONNECT_SUCCESS
,
500
)
}
else
{
notifyAlert
(
getString
(
R
.
string
.
forward_fail
),
getString
(
R
.
string
.
service_failed
))
stopSelf
()
handler
.
sendEmptyMessageDelayed
(
MSG_CONNECT_FAIL
,
500
)
}
handler
.
sendEmptyMessageDelayed
(
MSG_CONNECT_FINISH
,
500
)
}
}
def
startRedsocksDaemon
()
{
def
startRedsocksDaemon
()
{
val
conf
=
Config
.
REDSOCKS
.
format
(
config
.
localPort
)
val
conf
=
ConfigUtils
.
REDSOCKS
.
format
(
config
.
localPort
)
val
cmd
=
"%sredsocks -p %sredsocks.pid -c %sredsocks.conf"
.
format
(
Path
.
BASE
,
Path
.
BASE
,
Path
.
BASE
)
val
cmd
=
"%sredsocks -p %sredsocks.pid -c %sredsocks.conf"
Config
.
printToFile
(
new
File
(
Path
.
BASE
+
"redsocks.conf"
))(
p
=>
{
.
format
(
Path
.
BASE
,
Path
.
BASE
,
Path
.
BASE
)
ConfigUtils
.
printToFile
(
new
File
(
Path
.
BASE
+
"redsocks.conf"
))(
p
=>
{
p
.
println
(
conf
)
p
.
println
(
conf
)
})
})
Utils
.
runRootCommand
(
cmd
)
Utils
.
runRootCommand
(
cmd
)
...
@@ -291,14 +165,14 @@ class ShadowsocksService extends Service {
...
@@ -291,14 +165,14 @@ class ShadowsocksService extends Service {
try
{
try
{
t
.
join
(
300
)
t
.
join
(
300
)
}
catch
{
}
catch
{
case
ignored
:
InterruptedException
=>
{
case
ignored
:
InterruptedException
=>
}
}
}
!
t
.
isAlive
!
t
.
isAlive
}
}
/** Called when the activity is first created. */
/** Called when the activity is first created. */
def
handleConnection
:
Boolean
=
{
def
handleConnection
:
Boolean
=
{
startShadowsocksDaemon
()
startShadowsocksDaemon
()
startDnsDaemon
()
startDnsDaemon
()
startRedsocksDaemon
()
startRedsocksDaemon
()
...
@@ -308,23 +182,16 @@ class ShadowsocksService extends Service {
...
@@ -308,23 +182,16 @@ class ShadowsocksService extends Service {
true
true
}
}
def
initSoundVibrateLights
(
notification
:
Notification
)
{
notification
.
sound
=
null
notification
.
defaults
|=
Notification
.
DEFAULT_LIGHTS
}
def
invokeMethod
(
method
:
Method
,
args
:
Array
[
AnyRef
])
{
def
invokeMethod
(
method
:
Method
,
args
:
Array
[
AnyRef
])
{
try
{
try
{
method
.
invoke
(
this
,
mStartForegroundArgs
:
_
*
)
method
.
invoke
(
this
,
mStartForegroundArgs
:
_
*
)
}
catch
{
}
catch
{
case
e
:
InvocationTargetException
=>
{
case
e
:
InvocationTargetException
=>
Log
.
w
(
TAG
,
"Unable to invoke method"
,
e
)
Log
.
w
(
TAG
,
"Unable to invoke method"
,
e
)
}
case
e
:
IllegalAccessException
=>
case
e
:
IllegalAccessException
=>
{
Log
.
w
(
TAG
,
"Unable to invoke method"
,
e
)
Log
.
w
(
TAG
,
"Unable to invoke method"
,
e
)
}
}
}
}
}
def
notifyForegroundAlert
(
title
:
String
,
info
:
String
)
{
def
notifyForegroundAlert
(
title
:
String
,
info
:
String
)
{
notifyForegroundAlert
(
title
,
info
,
-
1
)
notifyForegroundAlert
(
title
,
info
,
-
1
)
...
@@ -340,8 +207,9 @@ class ShadowsocksService extends Service {
...
@@ -340,8 +207,9 @@ class ShadowsocksService extends Service {
val
icon
=
getResources
.
getDrawable
(
R
.
drawable
.
ic_stat_shadowsocks
)
val
icon
=
getResources
.
getDrawable
(
R
.
drawable
.
ic_stat_shadowsocks
)
if
(
rate
>=
0
)
{
if
(
rate
>=
0
)
{
val
bitmap
=
Utils
.
getBitmap
(
rate
.
toString
,
icon
.
getIntrinsicWidth
*
4
,
val
bitmap
=
Utils
icon
.
getIntrinsicHeight
*
4
,
Color
.
TRANSPARENT
)
.
getBitmap
(
rate
.
toString
,
icon
.
getIntrinsicWidth
*
4
,
icon
.
getIntrinsicHeight
*
4
,
Color
.
TRANSPARENT
)
builder
.
setLargeIcon
(
bitmap
)
builder
.
setLargeIcon
(
bitmap
)
if
(
rate
<
1000
)
{
if
(
rate
<
1000
)
{
...
@@ -352,7 +220,6 @@ class ShadowsocksService extends Service {
...
@@ -352,7 +220,6 @@ class ShadowsocksService extends Service {
}
else
{
}
else
{
builder
.
setSmallIcon
(
R
.
drawable
.
ic_stat_speed
,
1091
)
builder
.
setSmallIcon
(
R
.
drawable
.
ic_stat_speed
,
1091
)
}
}
}
else
{
}
else
{
builder
.
setSmallIcon
(
R
.
drawable
.
ic_stat_shadowsocks
)
builder
.
setSmallIcon
(
R
.
drawable
.
ic_stat_shadowsocks
)
}
}
...
@@ -386,20 +253,17 @@ class ShadowsocksService extends Service {
...
@@ -386,20 +253,17 @@ class ShadowsocksService extends Service {
}
}
def
onBind
(
intent
:
Intent
)
:
IBinder
=
{
def
onBind
(
intent
:
Intent
)
:
IBinder
=
{
if
(
classOf
[
ShadowsocksNatService
].
getName
equals
intent
.
getAction
)
{
binder
}
else
{
null
null
}
}
}
override
def
onCreate
()
{
override
def
onCreate
()
{
super
.
onCreate
()
super
.
onCreate
()
Config
.
refresh
(
this
)
ConfigUtils
.
refresh
(
this
)
EasyTracker
.
getInstance
(
this
)
.
send
(
MapBuilder
.
createEvent
(
TAG
,
"start"
,
getVersionName
,
0L
)
.
set
(
Fields
.
SESSION_CONTROL
,
"start"
)
.
build
())
notificationManager
=
this
notificationManager
=
this
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
...
@@ -408,65 +272,21 @@ class ShadowsocksService extends Service {
...
@@ -408,65 +272,21 @@ class ShadowsocksService extends Service {
mStartForeground
=
getClass
.
getMethod
(
"startForeground"
,
mStartForegroundSignature
:
_
*
)
mStartForeground
=
getClass
.
getMethod
(
"startForeground"
,
mStartForegroundSignature
:
_
*
)
mStopForeground
=
getClass
.
getMethod
(
"stopForeground"
,
mStopForegroundSignature
:
_
*
)
mStopForeground
=
getClass
.
getMethod
(
"stopForeground"
,
mStopForegroundSignature
:
_
*
)
}
catch
{
}
catch
{
case
e
:
NoSuchMethodException
=>
{
case
e
:
NoSuchMethodException
=>
mStartForeground
=
{
mStartForeground
=
{
mStopForeground
=
null
mStopForeground
=
null
mStopForeground
mStopForeground
}
}
}
}
}
try
{
try
{
mSetForeground
=
getClass
.
getMethod
(
"setForeground"
,
mSetForegroundSignature
:
_
*
)
mSetForeground
=
getClass
.
getMethod
(
"setForeground"
,
mSetForegroundSignature
:
_
*
)
}
catch
{
}
catch
{
case
e
:
NoSuchMethodException
=>
{
case
e
:
NoSuchMethodException
=>
throw
new
IllegalStateException
(
throw
new
IllegalStateException
(
"OS doesn't have Service.startForeground OR Service.setForeground!"
)
"OS doesn't have Service.startForeground OR Service.setForeground!"
)
}
}
}
}
// register close receiver
val
filter
=
new
IntentFilter
()
filter
.
addAction
(
Intent
.
ACTION_SHUTDOWN
)
filter
.
addAction
(
Action
.
CLOSE
)
receiver
=
new
BroadcastReceiver
()
{
def
onReceive
(
p1
:
Context
,
p2
:
Intent
)
{
stopSelf
()
}
}
registerReceiver
(
receiver
,
filter
)
}
/** Called when the activity is closed. */
override
def
onDestroy
()
{
// reset timer
if
(
timer
!=
null
)
{
timer
.
cancel
()
timer
=
null
}
// clean up context
changeState
(
State
.
STOPPED
)
EasyTracker
.
getInstance
(
this
)
.
send
(
MapBuilder
.
createEvent
(
TAG
,
"stop"
,
getVersionName
,
0L
)
.
set
(
Fields
.
SESSION_CONTROL
,
"stop"
)
.
build
())
stopForegroundCompat
(
1
)
if
(
receiver
!=
null
)
{
unregisterReceiver
(
receiver
)
receiver
=
null
}
// reset NAT
killProcesses
()
super
.
onDestroy
()
}
def
killProcesses
()
{
def
killProcesses
()
{
Utils
.
runRootCommand
(
Utils
.
getIptables
+
" -t nat -F OUTPUT"
)
Utils
.
runRootCommand
(
Utils
.
getIptables
+
" -t nat -F OUTPUT"
)
...
@@ -489,12 +309,7 @@ class ShadowsocksService extends Service {
...
@@ -489,12 +309,7 @@ class ShadowsocksService extends Service {
Utils
.
runCommand
(
sb
.
toString
())
Utils
.
runCommand
(
sb
.
toString
())
}
}
override
def
onStart
(
intent
:
Intent
,
startId
:
Int
)
{
handleCommand
(
intent
)
}
override
def
onStartCommand
(
intent
:
Intent
,
flags
:
Int
,
startId
:
Int
)
:
Int
=
{
override
def
onStartCommand
(
intent
:
Intent
,
flags
:
Int
,
startId
:
Int
)
:
Int
=
{
handleCommand
(
intent
)
Service
.
START_STICKY
Service
.
START_STICKY
}
}
...
@@ -593,17 +408,148 @@ class ShadowsocksService extends Service {
...
@@ -593,17 +408,148 @@ class ShadowsocksService extends Service {
try
{
try
{
mStopForeground
.
invoke
(
this
,
mStopForegroundArgs
:
_
*
)
mStopForeground
.
invoke
(
this
,
mStopForegroundArgs
:
_
*
)
}
catch
{
}
catch
{
case
e
:
InvocationTargetException
=>
{
case
e
:
InvocationTargetException
=>
Log
.
w
(
TAG
,
"Unable to invoke stopForeground"
,
e
)
Log
.
w
(
TAG
,
"Unable to invoke stopForeground"
,
e
)
}
case
e
:
IllegalAccessException
=>
case
e
:
IllegalAccessException
=>
{
Log
.
w
(
TAG
,
"Unable to invoke stopForeground"
,
e
)
Log
.
w
(
TAG
,
"Unable to invoke stopForeground"
,
e
)
}
}
}
return
return
}
}
notificationManager
.
cancel
(
id
)
notificationManager
.
cancel
(
id
)
mSetForegroundArgs
(
0
)
=
boolean2Boolean
(
x
=
false
)
mSetForegroundArgs
(
0
)
=
boolean2Boolean
(
x
=
false
)
invokeMethod
(
mSetForeground
,
mSetForegroundArgs
)
invokeMethod
(
mSetForeground
,
mSetForegroundArgs
)
}
}
override
def
startRunner
(
c
:
Config
)
{
config
=
c
// register close receiver
val
filter
=
new
IntentFilter
()
filter
.
addAction
(
Intent
.
ACTION_SHUTDOWN
)
filter
.
addAction
(
Action
.
CLOSE
)
receiver
=
new
BroadcastReceiver
()
{
def
onReceive
(
p1
:
Context
,
p2
:
Intent
)
{
stopRunner
()
}
}
registerReceiver
(
receiver
,
filter
)
// start tracker
EasyTracker
.
getInstance
(
this
)
.
send
(
MapBuilder
.
createEvent
(
TAG
,
"start"
,
getVersionName
,
0L
)
.
set
(
Fields
.
SESSION_CONTROL
,
"start"
)
.
build
())
changeState
(
State
.
CONNECTING
)
if
(
config
.
isTrafficStat
)
{
// initialize timer
val
task
=
new
TimerTask
{
def
run
()
{
val
pm
=
getSystemService
(
Context
.
POWER_SERVICE
).
asInstanceOf
[
PowerManager
]
val
now
=
new
TrafficStat
(
TrafficStats
.
getUidTxBytes
(
uid
),
TrafficStats
.
getUidRxBytes
(
uid
),
java
.
lang
.
System
.
currentTimeMillis
())
val
txRate
=
((
now
.
tx
-
last
.
tx
)
/
1024
/
TIMER_INTERVAL
).
toInt
val
rxRate
=
((
now
.
rx
-
last
.
rx
)
/
1024
/
TIMER_INTERVAL
).
toInt
last
=
now
if
(
lastTxRate
==
txRate
&&
lastRxRate
==
rxRate
)
{
return
}
else
{
lastTxRate
=
txRate
lastRxRate
=
rxRate
}
if
((
pm
.
isScreenOn
&&
state
==
State
.
CONNECTED
)
||
(
txRate
==
0
&&
rxRate
==
0
))
{
notifyForegroundAlert
(
getString
(
R
.
string
.
forward_success
),
getString
(
R
.
string
.
service_status
).
format
(
math
.
max
(
txRate
,
rxRate
)),
math
.
max
(
txRate
,
rxRate
))
}
}
}
last
=
new
TrafficStat
(
TrafficStats
.
getUidTxBytes
(
uid
),
TrafficStats
.
getUidRxBytes
(
uid
),
java
.
lang
.
System
.
currentTimeMillis
())
timer
=
new
Timer
(
true
)
timer
.
schedule
(
task
,
TIMER_INTERVAL
*
1000
,
TIMER_INTERVAL
*
1000
)
}
spawn
{
if
(
config
.
proxy
==
"198.199.101.152"
)
{
val
container
=
getApplication
.
asInstanceOf
[
ShadowsocksApplication
].
tagContainer
try
{
config
=
ConfigUtils
.
getPublicConfig
(
getBaseContext
,
container
,
config
)
}
catch
{
case
ex
:
Exception
=>
notifyAlert
(
getString
(
R
.
string
.
forward_fail
),
getString
(
R
.
string
.
service_failed
))
stopRunner
()
handler
.
sendEmptyMessageDelayed
(
Msg
.
CONNECT_FAIL
,
500
)
return
}
}
killProcesses
()
var
resolved
:
Boolean
=
false
if
(!
InetAddressUtils
.
isIPv4Address
(
config
.
proxy
)
&&
!
InetAddressUtils
.
isIPv6Address
(
config
.
proxy
))
{
Utils
.
resolve
(
config
.
proxy
,
enableIPv6
=
true
)
match
{
case
Some
(
a
)
=>
config
.
proxy
=
a
resolved
=
true
case
None
=>
resolved
=
false
}
}
else
{
resolved
=
true
}
hasRedirectSupport
=
Utils
.
getHasRedirectSupport
if
(
resolved
&&
handleConnection
)
{
notifyForegroundAlert
(
getString
(
R
.
string
.
forward_success
),
getString
(
R
.
string
.
service_running
).
format
(
config
.
profileName
))
handler
.
sendEmptyMessageDelayed
(
Msg
.
CONNECT_SUCCESS
,
500
)
}
else
{
notifyAlert
(
getString
(
R
.
string
.
forward_fail
),
getString
(
R
.
string
.
service_failed
))
stopRunner
()
handler
.
sendEmptyMessageDelayed
(
Msg
.
CONNECT_FAIL
,
500
)
}
handler
.
sendEmptyMessageDelayed
(
Msg
.
CONNECT_FINISH
,
500
)
}
}
override
def
stopRunner
()
{
// change the state
changeState
(
State
.
STOPPED
)
// stop the tracker
EasyTracker
.
getInstance
(
this
)
.
send
(
MapBuilder
.
createEvent
(
TAG
,
"stop"
,
getVersionName
,
0L
)
.
set
(
Fields
.
SESSION_CONTROL
,
"stop"
)
.
build
())
// reset timer
if
(
timer
!=
null
)
{
timer
.
cancel
()
timer
=
null
}
// clean up context
stopForegroundCompat
(
1
)
if
(
receiver
!=
null
)
{
unregisterReceiver
(
receiver
)
receiver
=
null
}
// reset NAT
killProcesses
()
}
override
def
getTag
=
TAG
override
def
getServiceMode
=
Mode
.
NAT
override
def
getContext
=
getBaseContext
}
}
src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala
View file @
0b8114ad
...
@@ -54,34 +54,17 @@ class ShadowsocksReceiver extends BroadcastReceiver {
...
@@ -54,34 +54,17 @@ class ShadowsocksReceiver extends BroadcastReceiver {
val
settings
:
SharedPreferences
=
PreferenceManager
.
getDefaultSharedPreferences
(
context
)
val
settings
:
SharedPreferences
=
PreferenceManager
.
getDefaultSharedPreferences
(
context
)
val
status
=
context
.
getSharedPreferences
(
Key
.
status
,
Context
.
MODE_PRIVATE
)
val
status
=
context
.
getSharedPreferences
(
Key
.
status
,
Context
.
MODE_PRIVATE
)
if
(
intent
.
getAction
==
Action
.
UPDATE_STATE
)
{
val
state
=
intent
.
getIntExtra
(
Extra
.
STATE
,
State
.
INIT
)
val
running
=
state
match
{
case
State
.
CONNECTING
=>
true
case
State
.
CONNECTED
=>
true
case
_
=>
false
}
status
.
edit
.
putBoolean
(
Key
.
isRunning
,
running
).
commit
()
return
}
var
versionName
:
String
=
null
var
versionName
:
String
=
null
try
{
try
{
versionName
=
context
.
getPackageManager
.
getPackageInfo
(
context
.
getPackageName
,
0
).
versionName
versionName
=
context
.
getPackageManager
.
getPackageInfo
(
context
.
getPackageName
,
0
).
versionName
}
catch
{
}
catch
{
case
e
:
PackageManager.NameNotFoundException
=>
{
case
e
:
PackageManager.NameNotFoundException
=>
versionName
=
"NONE"
versionName
=
"NONE"
}
}
}
val
isAutoConnect
:
Boolean
=
settings
.
getBoolean
(
Key
.
isAutoConnect
,
false
)
val
isAutoConnect
:
Boolean
=
settings
.
getBoolean
(
Key
.
isAutoConnect
,
false
)
val
isInstalled
:
Boolean
=
status
.
getBoolean
(
versionName
,
false
)
val
isInstalled
:
Boolean
=
status
.
getBoolean
(
versionName
,
false
)
if
(
isAutoConnect
&&
isInstalled
)
{
if
(
isAutoConnect
&&
isInstalled
)
{
if
(
Utils
.
getRoot
)
{
context
.
startActivity
(
new
Intent
(
context
,
classOf
[
ShadowsocksRunnerActivity
]))
if
(
ShadowsocksService
.
isServiceStarted
(
context
))
return
val
intent
:
Intent
=
new
Intent
(
context
,
classOf
[
ShadowsocksService
])
Extra
.
put
(
settings
,
intent
)
context
.
startService
(
intent
)
}
}
}
}
}
}
}
src/main/scala/com/github/shadowsocks/Shadow
Vpn
Activity.scala
→
src/main/scala/com/github/shadowsocks/Shadow
socksRunner
Activity.scala
View file @
0b8114ad
...
@@ -40,37 +40,74 @@
...
@@ -40,37 +40,74 @@
package
com.github.shadowsocks
package
com.github.shadowsocks
import
android.app.Activity
import
android.app.Activity
import
android.os.
Bundle
import
android.os.
{
IBinder
,
Bundle
}
import
android.net.VpnService
import
android.net.VpnService
import
android.content.
Intent
import
android.content.
{
Context
,
ComponentName
,
ServiceConnection
,
Intent
}
import
android.util.Log
import
android.util.Log
import
android.preference.PreferenceManager
import
android.preference.PreferenceManager
import
com.github.shadowsocks.utils.
Extra
import
com.github.shadowsocks.utils.
_
import
com.
actionbarsherlock.app.SherlockActivity
import
com.
github.shadowsocks.aidl.IShadowsocksService
class
Shadow
Vpn
Activity
extends
Activity
{
class
Shadow
socksRunner
Activity
extends
Activity
{
override
def
onCreate
(
savedInstanceState
:
Bundle
)
{
lazy
val
settings
=
PreferenceManager
.
getDefaultSharedPreferences
(
this
)
super
.
onCreate
(
savedInstanceState
)
lazy
val
isRoot
=
Utils
.
getRoot
val
intent
=
VpnService
.
prepare
(
this
)
// Services
var
bgService
:
IShadowsocksService
=
null
val
connection
=
new
ServiceConnection
{
override
def
onServiceConnected
(
name
:
ComponentName
,
service
:
IBinder
)
{
bgService
=
IShadowsocksService
.
Stub
.
asInterface
(
service
)
if
(!
isRoot
)
{
val
intent
=
VpnService
.
prepare
(
ShadowsocksRunnerActivity
.
this
)
if
(
intent
!=
null
)
{
if
(
intent
!=
null
)
{
startActivityForResult
(
intent
,
Shadowsocks
.
REQUEST_CONNECT
)
startActivityForResult
(
intent
,
Shadowsocks
.
REQUEST_CONNECT
)
}
else
{
}
else
{
onActivityResult
(
Shadowsocks
.
REQUEST_CONNECT
,
Activity
.
RESULT_OK
,
null
)
onActivityResult
(
Shadowsocks
.
REQUEST_CONNECT
,
Activity
.
RESULT_OK
,
null
)
}
}
}
else
{
bgService
.
start
(
ConfigUtils
.
load
(
settings
))
}
}
override
def
onServiceDisconnected
(
name
:
ComponentName
)
{
bgService
=
null
}
}
def
attachService
()
{
if
(
bgService
==
null
)
{
val
s
=
if
(
isRoot
)
classOf
[
ShadowsocksNatService
]
else
classOf
[
ShadowsocksVpnService
]
bindService
(
new
Intent
(
s
.
getName
),
connection
,
Context
.
BIND_AUTO_CREATE
)
startService
(
new
Intent
(
this
,
s
))
}
}
def
deattachService
()
{
if
(
bgService
!=
null
)
{
unbindService
(
connection
)
bgService
=
null
}
}
override
def
onCreate
(
savedInstanceState
:
Bundle
)
{
super
.
onCreate
(
savedInstanceState
)
attachService
()
}
override
def
onDestroy
()
{
super
.
onDestroy
()
deattachService
()
}
}
override
def
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
)
{
override
def
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
)
{
resultCode
match
{
resultCode
match
{
case
Activity
.
RESULT_OK
=>
{
case
Activity
.
RESULT_OK
=>
val
intent
:
Intent
=
new
Intent
(
this
,
classOf
[
ShadowVpnService
])
if
(
bgService
!=
null
)
{
Extra
.
put
(
PreferenceManager
.
getDefaultSharedPreferences
(
this
),
intent
)
bgService
.
start
(
ConfigUtils
.
load
(
settings
))
startService
(
intent
)
}
}
case
_
=>
{
case
_
=>
Log
.
e
(
Shadowsocks
.
TAG
,
"Failed to start VpnService"
)
Log
.
e
(
Shadowsocks
.
TAG
,
"Failed to start VpnService"
)
}
}
}
finish
()
finish
()
}
}
}
}
src/main/scala/com/github/shadowsocks/ShadowVpnService.scala
→
src/main/scala/com/github/shadowsocks/Shadow
socks
VpnService.scala
View file @
0b8114ad
...
@@ -56,22 +56,11 @@ import org.apache.commons.net.util.SubnetUtils
...
@@ -56,22 +56,11 @@ import org.apache.commons.net.util.SubnetUtils
import
java.net.InetAddress
import
java.net.InetAddress
import
com.github.shadowsocks.utils._
import
com.github.shadowsocks.utils._
import
scala.Some
import
scala.Some
import
com.github.shadowsocks.aidl.
{
IShadowsocksService
,
Config
}
object
ShadowVpnService
{
class
ShadowsocksVpnService
extends
VpnService
with
BaseService
{
def
isServiceStarted
(
context
:
Context
)
:
Boolean
=
{
Utils
.
isServiceStarted
(
"com.github.shadowsocks.ShadowVpnService"
,
context
)
}
}
class
ShadowVpnService
extends
VpnService
{
val
TAG
=
"ShadowVpnService"
val
TAG
=
"ShadowsocksVpnService"
val
MSG_CONNECT_FINISH
=
1
val
MSG_CONNECT_SUCCESS
=
2
val
MSG_CONNECT_FAIL
=
3
val
MSG_STOP_SELF
=
5
val
MSG_VPN_ERROR
=
6
val
VPN_MTU
=
1500
val
VPN_MTU
=
1500
...
@@ -83,60 +72,21 @@ class ShadowVpnService extends VpnService {
...
@@ -83,60 +72,21 @@ class ShadowVpnService extends VpnService {
var
apps
:
Array
[
ProxiedApp
]
=
null
var
apps
:
Array
[
ProxiedApp
]
=
null
var
config
:
Config
=
null
var
config
:
Config
=
null
private
var
state
=
State
.
INIT
private
var
message
:
String
=
null
def
changeState
(
s
:
Int
)
{
changeState
(
s
,
null
)
}
def
changeState
(
s
:
Int
,
m
:
String
)
{
if
(
state
!=
s
)
{
state
=
s
if
(
m
!=
null
)
message
=
m
val
intent
=
new
Intent
(
Action
.
UPDATE_STATE
)
intent
.
putExtra
(
Extra
.
STATE
,
state
)
intent
.
putExtra
(
Extra
.
MESSAGE
,
message
)
sendBroadcast
(
intent
)
}
}
val
handler
:
Handler
=
new
Handler
{
val
handler
:
Handler
=
new
Handler
{
override
def
handleMessage
(
msg
:
Message
)
{
override
def
handleMessage
(
msg
:
Message
)
{
msg
.
what
match
{
msg
.
what
match
{
case
M
SG_
CONNECT_SUCCESS
=>
case
M
sg
.
CONNECT_SUCCESS
=>
changeState
(
State
.
CONNECTED
)
changeState
(
State
.
CONNECTED
)
case
M
SG_
CONNECT_FAIL
=>
case
M
sg
.
CONNECT_FAIL
=>
changeState
(
State
.
STOPPED
)
changeState
(
State
.
STOPPED
)
case
M
SG_
VPN_ERROR
=>
case
M
sg
.
VPN_ERROR
=>
if
(
msg
.
obj
!=
null
)
changeState
(
State
.
STOPPED
,
msg
.
obj
.
asInstanceOf
[
String
])
if
(
msg
.
obj
!=
null
)
changeState
(
State
.
STOPPED
,
msg
.
obj
.
asInstanceOf
[
String
])
case
MSG_STOP_SELF
=>
stopSelf
()
case
_
=>
case
_
=>
}
}
super
.
handleMessage
(
msg
)
super
.
handleMessage
(
msg
)
}
}
}
}
def
getPid
(
name
:
String
)
:
Int
=
{
try
{
val
reader
:
BufferedReader
=
new
BufferedReader
(
new
FileReader
(
Path
.
BASE
+
name
+
".pid"
))
val
line
=
reader
.
readLine
return
Integer
.
valueOf
(
line
)
}
catch
{
case
e
:
FileNotFoundException
=>
{
Log
.
e
(
TAG
,
"Cannot open pid file: "
+
name
)
}
case
e
:
IOException
=>
{
Log
.
e
(
TAG
,
"Cannot read pid file: "
+
name
)
}
case
e
:
NumberFormatException
=>
{
Log
.
e
(
TAG
,
"Invalid pid"
,
e
)
}
}
-
1
}
def
startShadowsocksDaemon
()
{
def
startShadowsocksDaemon
()
{
val
cmd
:
String
=
(
Path
.
BASE
+
val
cmd
:
String
=
(
Path
.
BASE
+
"shadowsocks -b 127.0.0.1 -s \"%s\" -p \"%d\" -l \"%d\" -k \"%s\" -m \"%s\" -f "
+
"shadowsocks -b 127.0.0.1 -s \"%s\" -p \"%d\" -l \"%d\" -k \"%s\" -m \"%s\" -f "
+
...
@@ -148,8 +98,8 @@ class ShadowVpnService extends VpnService {
...
@@ -148,8 +98,8 @@ class ShadowVpnService extends VpnService {
def
startDnsDaemon
()
{
def
startDnsDaemon
()
{
val
cmd
:
String
=
Path
.
BASE
+
"pdnsd -c "
+
Path
.
BASE
+
"pdnsd.conf"
val
cmd
:
String
=
Path
.
BASE
+
"pdnsd -c "
+
Path
.
BASE
+
"pdnsd.conf"
val
conf
:
String
=
Config
.
PDNSD
.
format
(
"0.0.0.0"
)
val
conf
:
String
=
Config
Utils
.
PDNSD
.
format
(
"0.0.0.0"
)
Config
.
printToFile
(
new
File
(
Path
.
BASE
+
"pdnsd.conf"
))(
p
=>
{
Config
Utils
.
printToFile
(
new
File
(
Path
.
BASE
+
"pdnsd.conf"
))(
p
=>
{
p
.
println
(
conf
)
p
.
println
(
conf
)
})
})
Utils
.
runCommand
(
cmd
)
Utils
.
runCommand
(
cmd
)
...
@@ -161,74 +111,12 @@ class ShadowVpnService extends VpnService {
...
@@ -161,74 +111,12 @@ class ShadowVpnService extends VpnService {
val
pi
:
PackageInfo
=
getPackageManager
.
getPackageInfo
(
getPackageName
,
0
)
val
pi
:
PackageInfo
=
getPackageManager
.
getPackageInfo
(
getPackageName
,
0
)
version
=
pi
.
versionName
version
=
pi
.
versionName
}
catch
{
}
catch
{
case
e
:
PackageManager.NameNotFoundException
=>
{
case
e
:
PackageManager.NameNotFoundException
=>
version
=
"Package name not found"
version
=
"Package name not found"
}
}
}
version
version
}
}
def
handleCommand
(
intent
:
Intent
)
{
if
(
intent
==
null
)
{
stopSelf
()
return
}
if
(
VpnService
.
prepare
(
this
)
!=
null
)
{
val
i
=
new
Intent
(
this
,
classOf
[
ShadowVpnActivity
])
i
.
addFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
)
startActivity
(
i
)
stopSelf
()
return
}
changeState
(
State
.
CONNECTING
)
config
=
Extra
.
get
(
intent
)
spawn
{
if
(
config
.
proxy
==
"198.199.101.152"
)
{
val
container
=
getApplication
.
asInstanceOf
[
ShadowsocksApplication
].
tagContainer
try
{
config
=
Config
.
getPublicConfig
(
getBaseContext
,
container
,
config
)
}
catch
{
case
ex
:
Exception
=>
{
notifyAlert
(
getString
(
R
.
string
.
forward_fail
),
getString
(
R
.
string
.
service_failed
))
stopSelf
()
handler
.
sendEmptyMessageDelayed
(
MSG_CONNECT_FAIL
,
500
)
return
}
}
}
killProcesses
()
// Resolve server address
var
resolved
:
Boolean
=
false
if
(!
InetAddressUtils
.
isIPv4Address
(
config
.
proxy
)
&&
!
InetAddressUtils
.
isIPv6Address
(
config
.
proxy
))
{
Utils
.
resolve
(
config
.
proxy
,
enableIPv6
=
true
)
match
{
case
Some
(
addr
)
=>
config
.
proxy
=
addr
resolved
=
true
case
None
=>
resolved
=
false
}
}
else
{
resolved
=
true
}
if
(
resolved
&&
handleConnection
)
{
handler
.
sendEmptyMessageDelayed
(
MSG_CONNECT_SUCCESS
,
300
)
}
else
{
notifyAlert
(
getString
(
R
.
string
.
forward_fail
),
getString
(
R
.
string
.
service_failed
))
handler
.
sendEmptyMessageDelayed
(
MSG_CONNECT_FAIL
,
300
)
handler
.
sendEmptyMessageDelayed
(
MSG_STOP_SELF
,
500
)
}
handler
.
sendEmptyMessageDelayed
(
MSG_CONNECT_FINISH
,
300
)
}
}
def
waitForProcess
(
name
:
String
)
:
Boolean
=
{
def
waitForProcess
(
name
:
String
)
:
Boolean
=
{
val
pid
:
Int
=
getPid
(
name
)
val
pid
:
Int
=
getPid
(
name
)
if
(
pid
==
-
1
)
return
false
if
(
pid
==
-
1
)
return
false
...
@@ -242,8 +130,7 @@ class ShadowVpnService extends VpnService {
...
@@ -242,8 +130,7 @@ class ShadowVpnService extends VpnService {
try
{
try
{
t
.
join
(
300
)
t
.
join
(
300
)
}
catch
{
}
catch
{
case
ignored
:
InterruptedException
=>
{
case
ignored
:
InterruptedException
=>
}
}
}
!
t
.
isAlive
!
t
.
isAlive
}
}
...
@@ -308,18 +195,17 @@ class ShadowVpnService extends VpnService {
...
@@ -308,18 +195,17 @@ class ShadowVpnService extends VpnService {
try
{
try
{
conn
=
builder
.
establish
()
conn
=
builder
.
establish
()
}
catch
{
}
catch
{
case
ex
:
IllegalStateException
=>
{
case
ex
:
IllegalStateException
=>
val
msg
=
new
Message
()
val
msg
=
new
Message
()
msg
.
what
=
M
SG_
VPN_ERROR
msg
.
what
=
M
sg
.
VPN_ERROR
msg
.
obj
=
ex
.
getMessage
msg
.
obj
=
ex
.
getMessage
handler
.
sendMessage
(
msg
)
handler
.
sendMessage
(
msg
)
conn
=
null
conn
=
null
}
case
ex
:
Exception
=>
conn
=
null
case
ex
:
Exception
=>
conn
=
null
}
}
if
(
conn
==
null
)
{
if
(
conn
==
null
)
{
stop
Self
()
stop
Runner
()
return
return
}
}
...
@@ -348,11 +234,6 @@ class ShadowVpnService extends VpnService {
...
@@ -348,11 +234,6 @@ class ShadowVpnService extends VpnService {
true
true
}
}
def
initSoundVibrateLights
(
notification
:
Notification
)
{
notification
.
sound
=
null
notification
.
defaults
|=
Notification
.
DEFAULT_LIGHTS
}
def
notifyAlert
(
title
:
String
,
info
:
String
)
{
def
notifyAlert
(
title
:
String
,
info
:
String
)
{
val
openIntent
:
Intent
=
new
Intent
(
this
,
classOf
[
Shadowsocks
])
val
openIntent
:
Intent
=
new
Intent
(
this
,
classOf
[
Shadowsocks
])
openIntent
.
setFlags
(
Intent
.
FLAG_ACTIVITY_CLEAR_TOP
)
openIntent
.
setFlags
(
Intent
.
FLAG_ACTIVITY_CLEAR_TOP
)
...
@@ -373,6 +254,8 @@ class ShadowVpnService extends VpnService {
...
@@ -373,6 +254,8 @@ class ShadowVpnService extends VpnService {
val
action
=
intent
.
getAction
val
action
=
intent
.
getAction
if
(
VpnService
.
SERVICE_INTERFACE
==
action
)
{
if
(
VpnService
.
SERVICE_INTERFACE
==
action
)
{
return
super
.
onBind
(
intent
)
return
super
.
onBind
(
intent
)
}
else
if
(
classOf
[
ShadowsocksVpnService
].
getName
==
action
)
{
return
binder
}
}
null
null
}
}
...
@@ -380,8 +263,47 @@ class ShadowVpnService extends VpnService {
...
@@ -380,8 +263,47 @@ class ShadowVpnService extends VpnService {
override
def
onCreate
()
{
override
def
onCreate
()
{
super
.
onCreate
()
super
.
onCreate
()
Config
.
refresh
(
this
)
ConfigUtils
.
refresh
(
this
)
notificationManager
=
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
.
asInstanceOf
[
NotificationManager
]
}
def
killProcesses
()
{
val
sb
=
new
StringBuilder
if
(!
waitForProcess
(
"shadowsocks"
))
{
sb
++=
"kill -9 `cat /data/data/com.github.shadowsocks/shadowsocks.pid`"
++=
"\n"
sb
++=
"killall -9 shadowsocks"
++=
"\n"
}
if
(!
waitForProcess
(
"tun2socks"
))
{
sb
++=
"kill -9 `cat /data/data/com.github.shadowsocks/tun2socks.pid`"
++=
"\n"
sb
++=
"killall -9 tun2socks"
++=
"\n"
}
if
(!
waitForProcess
(
"pdnsd"
))
{
sb
++=
"kill -9 `cat /data/data/com.github.shadowsocks/pdnsd.pid`"
++=
"\n"
sb
++=
"killall -9 pdnsd"
++=
"\n"
}
Utils
.
runCommand
(
sb
.
toString
())
}
override
def
onStartCommand
(
intent
:
Intent
,
flags
:
Int
,
startId
:
Int
)
:
Int
=
{
Service
.
START_STICKY
}
override
def
startRunner
(
c
:
Config
)
{
config
=
c
// ensure the VPNService is prepared
if
(
VpnService
.
prepare
(
this
)
!=
null
)
{
val
i
=
new
Intent
(
this
,
classOf
[
ShadowsocksRunnerActivity
])
i
.
addFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
)
startActivity
(
i
)
return
}
// start the tracker
EasyTracker
EasyTracker
.
getInstance
(
this
)
.
getInstance
(
this
)
.
send
(
MapBuilder
.
send
(
MapBuilder
...
@@ -389,26 +311,66 @@ class ShadowVpnService extends VpnService {
...
@@ -389,26 +311,66 @@ class ShadowVpnService extends VpnService {
.
set
(
Fields
.
SESSION_CONTROL
,
"start"
)
.
set
(
Fields
.
SESSION_CONTROL
,
"start"
)
.
build
())
.
build
())
notificationManager
=
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
.
asInstanceOf
[
NotificationManager
]
// register close receiver
// register close receiver
val
filter
=
new
IntentFilter
()
val
filter
=
new
IntentFilter
()
filter
.
addAction
(
Intent
.
ACTION_SHUTDOWN
)
filter
.
addAction
(
Intent
.
ACTION_SHUTDOWN
)
filter
.
addAction
(
Action
.
CLOSE
)
receiver
=
new
BroadcastReceiver
{
receiver
=
new
BroadcastReceiver
{
def
onReceive
(
p1
:
Context
,
p2
:
Intent
)
{
def
onReceive
(
p1
:
Context
,
p2
:
Intent
)
{
stop
Self
()
stop
Runner
()
}
}
}
}
registerReceiver
(
receiver
,
filter
)
registerReceiver
(
receiver
,
filter
)
changeState
(
State
.
CONNECTING
)
spawn
{
if
(
config
.
proxy
==
"198.199.101.152"
)
{
val
container
=
getApplication
.
asInstanceOf
[
ShadowsocksApplication
].
tagContainer
try
{
config
=
ConfigUtils
.
getPublicConfig
(
getBaseContext
,
container
,
config
)
}
catch
{
case
ex
:
Exception
=>
notifyAlert
(
getString
(
R
.
string
.
forward_fail
),
getString
(
R
.
string
.
service_failed
))
stopRunner
()
handler
.
sendEmptyMessageDelayed
(
Msg
.
CONNECT_FAIL
,
500
)
return
}
}
}
override
def
onDestroy
()
{
// reset the context
killProcesses
()
killProcesses
()
// Resolve the server address
var
resolved
:
Boolean
=
false
if
(!
InetAddressUtils
.
isIPv4Address
(
config
.
proxy
)
&&
!
InetAddressUtils
.
isIPv6Address
(
config
.
proxy
))
{
Utils
.
resolve
(
config
.
proxy
,
enableIPv6
=
true
)
match
{
case
Some
(
addr
)
=>
config
.
proxy
=
addr
resolved
=
true
case
None
=>
resolved
=
false
}
}
else
{
resolved
=
true
}
if
(
resolved
&&
handleConnection
)
{
handler
.
sendEmptyMessageDelayed
(
Msg
.
CONNECT_SUCCESS
,
300
)
}
else
{
notifyAlert
(
getString
(
R
.
string
.
forward_fail
),
getString
(
R
.
string
.
service_failed
))
handler
.
sendEmptyMessageDelayed
(
Msg
.
CONNECT_FAIL
,
300
)
stopRunner
()
}
handler
.
sendEmptyMessageDelayed
(
Msg
.
CONNECT_FINISH
,
300
)
}
}
override
def
stopRunner
()
{
// channge the state
changeState
(
State
.
STOPPED
)
changeState
(
State
.
STOPPED
)
// stop the tracker
EasyTracker
EasyTracker
.
getInstance
(
this
)
.
getInstance
(
this
)
.
send
(
MapBuilder
.
send
(
MapBuilder
...
@@ -416,45 +378,26 @@ class ShadowVpnService extends VpnService {
...
@@ -416,45 +378,26 @@ class ShadowVpnService extends VpnService {
.
set
(
Fields
.
SESSION_CONTROL
,
"stop"
)
.
set
(
Fields
.
SESSION_CONTROL
,
"stop"
)
.
build
())
.
build
())
// clean up the context
if
(
receiver
!=
null
)
{
if
(
receiver
!=
null
)
{
unregisterReceiver
(
receiver
)
unregisterReceiver
(
receiver
)
receiver
=
null
receiver
=
null
}
}
// reset VPN
killProcesses
()
// close connections
if
(
conn
!=
null
)
{
if
(
conn
!=
null
)
{
conn
.
close
()
conn
.
close
()
conn
=
null
conn
=
null
}
}
// reset notifications
notificationManager
.
cancel
(
1
)
notificationManager
.
cancel
(
1
)
super
.
onDestroy
()
}
def
killProcesses
()
{
val
sb
=
new
StringBuilder
if
(!
waitForProcess
(
"shadowsocks"
))
{
sb
++=
"kill -9 `cat /data/data/com.github.shadowsocks/shadowsocks.pid`"
++=
"\n"
sb
++=
"killall -9 shadowsocks"
++=
"\n"
}
if
(!
waitForProcess
(
"tun2socks"
))
{
sb
++=
"kill -9 `cat /data/data/com.github.shadowsocks/tun2socks.pid`"
++=
"\n"
sb
++=
"killall -9 tun2socks"
++=
"\n"
}
if
(!
waitForProcess
(
"pdnsd"
))
{
sb
++=
"kill -9 `cat /data/data/com.github.shadowsocks/pdnsd.pid`"
++=
"\n"
sb
++=
"killall -9 pdnsd"
++=
"\n"
}
Utils
.
runCommand
(
sb
.
toString
())
}
override
def
onStart
(
intent
:
Intent
,
startId
:
Int
)
{
handleCommand
(
intent
)
}
override
def
onStartCommand
(
intent
:
Intent
,
flags
:
Int
,
startId
:
Int
)
:
Int
=
{
handleCommand
(
intent
)
Service
.
START_STICKY
}
}
override
def
getTag
=
TAG
override
def
getServiceMode
=
Mode
.
VPN
override
def
getContext
=
getBaseContext
}
}
src/main/scala/com/github/shadowsocks/utils/Config.scala
→
src/main/scala/com/github/shadowsocks/utils/Config
Utils
.scala
View file @
0b8114ad
package
com.github.shadowsocks.utils
package
com.github.shadowsocks.utils
import
android.content.
Context
import
android.content.
{
Intent
,
SharedPreferences
,
Context
}
import
com.github.shadowsocks.ShadowsocksApplication
import
com.github.shadowsocks.ShadowsocksApplication
import
com.google.tagmanager.Container
import
com.google.tagmanager.Container
import
scalaj.http.
{
HttpOptions
,
Http
}
import
scalaj.http.
{
HttpOptions
,
Http
}
import
com.github.shadowsocks.aidl.Config
object
Config
{
object
Config
Utils
{
val
SHADOWSOCKS
=
"{\"server\": [%s], \"server_port\": %d, \"local_port\": %d, \"password\": %s, \"timeout\": %d}"
val
SHADOWSOCKS
=
"{\"server\": [%s], \"server_port\": %d, \"local_port\": %d, \"password\": %s, \"timeout\": %d}"
val
REDSOCKS
=
"base {"
+
val
REDSOCKS
=
"base {"
+
" log_debug = off;"
+
" log_debug = off;"
+
...
@@ -83,10 +84,35 @@ object Config {
...
@@ -83,10 +84,35 @@ object Config {
val
method
=
proxy
(
3
).
trim
val
method
=
proxy
(
3
).
trim
new
Config
(
config
.
isGlobalProxy
,
config
.
isGFWList
,
config
.
isBypassApps
,
config
.
isTrafficStat
,
new
Config
(
config
.
isGlobalProxy
,
config
.
isGFWList
,
config
.
isBypassApps
,
config
.
isTrafficStat
,
config
.
profileName
,
host
,
password
,
method
,
port
,
config
.
localPort
,
config
.
proxiedAppString
)
config
.
profileName
,
host
,
password
,
method
,
config
.
proxiedAppString
,
port
,
config
.
localPort
)
}
}
}
case
class
Config
(
isGlobalProxy
:
Boolean
,
isGFWList
:
Boolean
,
isBypassApps
:
Boolean
,
def
load
(
settings
:
SharedPreferences
)
:
Config
=
{
isTrafficStat
:
Boolean
,
profileName
:
String
,
var
proxy
:
String
,
sitekey
:
String
,
val
isGlobalProxy
=
settings
.
getBoolean
(
Key
.
isGlobalProxy
,
false
)
encMethod
:
String
,
remotePort
:
Int
,
localPort
:
Int
,
proxiedAppString
:
String
)
val
isGFWList
=
settings
.
getBoolean
(
Key
.
isGFWList
,
false
)
val
isBypassApps
=
settings
.
getBoolean
(
Key
.
isBypassApps
,
false
)
val
isTrafficStat
=
settings
.
getBoolean
(
Key
.
isTrafficStat
,
false
)
val
profileName
=
settings
.
getString
(
Key
.
profileName
,
"default"
)
val
proxy
=
settings
.
getString
(
Key
.
proxy
,
"127.0.0.1"
)
val
sitekey
=
settings
.
getString
(
Key
.
sitekey
,
"default"
)
val
encMethod
=
settings
.
getString
(
Key
.
encMethod
,
"table"
)
val
remotePort
:
Int
=
try
{
settings
.
getString
(
Key
.
remotePort
,
"1984"
).
toInt
}
catch
{
case
ex
:
NumberFormatException
=>
1984
}
val
localPort
:
Int
=
try
{
settings
.
getString
(
Key
.
localPort
,
"1984"
).
toInt
}
catch
{
case
ex
:
NumberFormatException
=>
1984
}
val
proxiedAppString
=
settings
.
getString
(
Key
.
proxied
,
""
)
new
Config
(
isGlobalProxy
,
isGFWList
,
isBypassApps
,
isTrafficStat
,
profileName
,
proxy
,
sitekey
,
encMethod
,
proxiedAppString
,
remotePort
,
localPort
)
}
}
\ No newline at end of file
src/main/scala/com/github/shadowsocks/utils/Constants.scala
View file @
0b8114ad
package
com.github.shadowsocks.utils
package
com.github.shadowsocks.utils
import
android.content.
{
Intent
,
SharedPreferences
}
import
android.content.
{
Intent
,
SharedPreferences
}
import
com.github.shadowsocks.aidl.Config
object
Msg
{
val
CONNECT_FINISH
=
1
val
CONNECT_SUCCESS
=
2
val
CONNECT_FAIL
=
3
val
VPN_ERROR
=
6
}
object
Path
{
object
Path
{
val
BASE
=
"/data/data/com.github.shadowsocks/"
val
BASE
=
"/data/data/com.github.shadowsocks/"
...
@@ -37,100 +45,21 @@ object Scheme {
...
@@ -37,100 +45,21 @@ object Scheme {
val
SS
=
"ss"
val
SS
=
"ss"
}
}
object
Mode
{
val
NAT
=
0
val
VPN
=
1
}
object
State
{
object
State
{
val
INIT
=
0
val
INIT
=
0
val
CONNECTING
=
1
val
CONNECTING
=
1
val
CONNECTED
=
2
val
CONNECTED
=
2
val
STOPPED
=
3
val
STOPPED
=
3
def
isAvailable
(
state
:
Int
)
:
Boolean
=
state
!=
CONNECTED
&&
state
!=
CONNECTING
}
}
object
Action
{
object
Action
{
val
CLOSE
=
"com.github.shadowsocks.ACTION_SHUTDOWN"
val
CLOSE
=
"com.github.shadowsocks.CLOSE"
val
UPDATE_STATE
=
"com.github.shadowsocks.ACTION_UPDATE_STATE"
val
UPDATE_FRAGMENT
=
"com.github.shadowsocks.ACTION_UPDATE_FRAGMENT"
val
UPDATE_FRAGMENT
=
"com.github.shadowsocks.ACTION_UPDATE_FRAGMENT"
val
UPDATE_PREFS
=
"com.github.shadowsocks.ACTION_UPDATE_PREFS"
val
UPDATE_PREFS
=
"com.github.shadowsocks.ACTION_UPDATE_PREFS"
}
}
\ No newline at end of file
object
Extra
{
val
STATE
=
"state"
val
MESSAGE
=
"message"
def
save
(
settings
:
SharedPreferences
,
config
:
Config
)
{
val
edit
=
settings
.
edit
()
edit
.
putBoolean
(
Key
.
isGlobalProxy
,
config
.
isGlobalProxy
)
edit
.
putBoolean
(
Key
.
isGFWList
,
config
.
isGFWList
)
edit
.
putBoolean
(
Key
.
isBypassApps
,
config
.
isBypassApps
)
edit
.
putBoolean
(
Key
.
isTrafficStat
,
config
.
isTrafficStat
)
edit
.
putString
(
Key
.
profileName
,
config
.
profileName
)
edit
.
putString
(
Key
.
proxy
,
config
.
proxy
)
edit
.
putString
(
Key
.
sitekey
,
config
.
sitekey
)
edit
.
putString
(
Key
.
encMethod
,
config
.
encMethod
)
edit
.
putString
(
Key
.
remotePort
,
config
.
remotePort
.
toString
)
edit
.
putString
(
Key
.
localPort
,
config
.
localPort
.
toString
)
edit
.
apply
()
}
def
get
(
intent
:
Intent
)
:
Config
=
{
val
isGlobalProxy
=
intent
.
getBooleanExtra
(
Key
.
isGlobalProxy
,
false
)
val
isGFWList
=
intent
.
getBooleanExtra
(
Key
.
isGFWList
,
false
)
val
isBypassApps
=
intent
.
getBooleanExtra
(
Key
.
isBypassApps
,
false
)
val
isTrafficStat
=
intent
.
getBooleanExtra
(
Key
.
isTrafficStat
,
false
)
val
profileName
=
intent
.
getStringExtra
(
Key
.
profileName
)
val
proxy
=
intent
.
getStringExtra
(
Key
.
proxy
)
val
sitekey
=
intent
.
getStringExtra
(
Key
.
sitekey
)
val
encMethod
=
intent
.
getStringExtra
(
Key
.
encMethod
)
val
remotePort
=
intent
.
getIntExtra
(
Key
.
remotePort
,
1984
)
val
localPort
=
intent
.
getIntExtra
(
Key
.
localPort
,
1984
)
val
proxiedString
=
intent
.
getStringExtra
(
Key
.
proxied
)
new
Config
(
isGlobalProxy
,
isGFWList
,
isBypassApps
,
isTrafficStat
,
profileName
,
proxy
,
sitekey
,
encMethod
,
remotePort
,
localPort
,
proxiedString
)
}
def
put
(
settings
:
SharedPreferences
,
intent
:
Intent
)
{
val
isGlobalProxy
=
settings
.
getBoolean
(
Key
.
isGlobalProxy
,
false
)
val
isGFWList
=
settings
.
getBoolean
(
Key
.
isGFWList
,
false
)
val
isBypassApps
=
settings
.
getBoolean
(
Key
.
isBypassApps
,
false
)
val
isTrafficStat
=
settings
.
getBoolean
(
Key
.
isTrafficStat
,
false
)
val
profileName
=
settings
.
getString
(
Key
.
profileName
,
"default"
)
val
proxy
=
settings
.
getString
(
Key
.
proxy
,
"127.0.0.1"
)
val
sitekey
=
settings
.
getString
(
Key
.
sitekey
,
"default"
)
val
encMethod
=
settings
.
getString
(
Key
.
encMethod
,
"table"
)
val
remotePort
:
Int
=
try
{
settings
.
getString
(
Key
.
remotePort
,
"1984"
).
toInt
}
catch
{
case
ex
:
NumberFormatException
=>
{
1984
}
}
val
localProt
:
Int
=
try
{
settings
.
getString
(
Key
.
localPort
,
"1984"
).
toInt
}
catch
{
case
ex
:
NumberFormatException
=>
{
1984
}
}
val
proxiedAppString
=
settings
.
getString
(
Key
.
proxied
,
""
)
intent
.
putExtra
(
Key
.
isGlobalProxy
,
isGlobalProxy
)
intent
.
putExtra
(
Key
.
isGFWList
,
isGFWList
)
intent
.
putExtra
(
Key
.
isBypassApps
,
isBypassApps
)
intent
.
putExtra
(
Key
.
isTrafficStat
,
isTrafficStat
)
intent
.
putExtra
(
Key
.
profileName
,
profileName
)
intent
.
putExtra
(
Key
.
proxy
,
proxy
)
intent
.
putExtra
(
Key
.
sitekey
,
sitekey
)
intent
.
putExtra
(
Key
.
encMethod
,
encMethod
)
intent
.
putExtra
(
Key
.
remotePort
,
remotePort
)
intent
.
putExtra
(
Key
.
localPort
,
localProt
)
intent
.
putExtra
(
Key
.
proxied
,
proxiedAppString
)
}
}
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