Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4e1a42146 | ||
|
|
76108ec450 | ||
|
|
5b9a0d0659 | ||
|
|
6558f275fe | ||
|
|
c13cf6f5d2 | ||
|
|
cacde5cff1 | ||
|
|
bb2bd82d73 | ||
|
|
0a46eedba1 | ||
|
|
63bc60e513 | ||
|
|
d9eb0e5163 | ||
|
|
fc3d26d626 | ||
|
|
1bb3a6bf5d | ||
|
|
f6cab9b99c | ||
|
|
a24d29196f | ||
|
|
2eb12ee2ae | ||
|
|
ef7701982d |
@@ -2,9 +2,7 @@
|
||||
|
||||
A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
|
||||
|
||||
Help to translate shadowsocks: http://crowdin.net/project/shadowsocks/invite
|
||||
|
||||
[](https://play.google.com/store/apps/details?id=com.github.shadowsocks)
|
||||
<a href="https://play.google.com/store/apps/details?id=com.github.shadowsocks"><img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png" height="48"></a>
|
||||
|
||||
### CI STATUS
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
resolvers += Resolver.url("scalasbt releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-snapshots"))(Resolver.ivyStylePatterns)
|
||||
|
||||
addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.5.17")
|
||||
addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.5.18")
|
||||
|
||||
resolvers += "Sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.github.shadowsocks"
|
||||
android:versionCode="131"
|
||||
android:versionName="2.9.9">
|
||||
android:versionCode="133"
|
||||
android:versionName="2.9.11">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
|
||||
@@ -4,16 +4,15 @@ import android.content.{ComponentName, Context, Intent, ServiceConnection}
|
||||
import android.os.{RemoteException, IBinder}
|
||||
import com.github.shadowsocks.aidl.{IShadowsocksServiceCallback, IShadowsocksService}
|
||||
import com.github.shadowsocks.utils.Action
|
||||
import com.github.shadowsocks.utils.Utils
|
||||
|
||||
/**
|
||||
* @author Mygod
|
||||
*/
|
||||
trait ServiceBoundContext extends Context {
|
||||
|
||||
trait ServiceBoundContext extends Context { outer =>
|
||||
class ShadowsocksServiceConnection extends ServiceConnection {
|
||||
override def onServiceConnected(name: ComponentName, service: IBinder) {
|
||||
bgService = IShadowsocksService.Stub.asInterface(service)
|
||||
bgService.asBinder().linkToDeath(new ShadowsocksDeathRecipient(outer), 0)
|
||||
registerCallback
|
||||
ServiceBoundContext.this.onServiceConnected()
|
||||
}
|
||||
@@ -33,11 +32,12 @@ trait ServiceBoundContext extends Context {
|
||||
} catch {
|
||||
case ignored: RemoteException => // Nothing
|
||||
}
|
||||
|
||||
def unregisterCallback = if (bgService != null && callback != null && callbackRegistered) try {
|
||||
bgService.unregisterCallback(callback)
|
||||
callbackRegistered = false
|
||||
} catch {
|
||||
case ignored: RemoteException => // Nothing
|
||||
case ignored: RemoteException => callbackRegistered = false
|
||||
}
|
||||
|
||||
def onServiceConnected() = ()
|
||||
|
||||
@@ -377,7 +377,11 @@ class Shadowsocks
|
||||
})
|
||||
updateTraffic(0, 0, 0, 0)
|
||||
|
||||
// Bind to the service
|
||||
bindToService()
|
||||
}
|
||||
|
||||
// Bind to the service
|
||||
def bindToService() {
|
||||
handler.post(() => attachService)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.github.shadowsocks
|
||||
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import com.github.shadowsocks.utils.ProcessUtils._
|
||||
|
||||
/**
|
||||
* @author chentaov5@gmail.com
|
||||
*/
|
||||
class ShadowsocksDeathRecipient(val mContext: ServiceBoundContext)
|
||||
extends IBinder.DeathRecipient {
|
||||
|
||||
val TAG = "ShadowsocksDeathRecipient"
|
||||
|
||||
override def binderDied(): Unit = {
|
||||
Log.d(TAG, "[ShadowsocksDeathRecipient] binder died.")
|
||||
|
||||
mContext match {
|
||||
case ss: Shadowsocks =>
|
||||
inShadowsocks(mContext) {
|
||||
ss.unregisterCallback
|
||||
ss.bindToService()
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -260,7 +260,7 @@ class ShadowsocksNatService extends BaseService {
|
||||
|
||||
def startDnsDaemon() {
|
||||
|
||||
val conf = if (config.route == Route.BYPASS_CHN) {
|
||||
val conf = if (config.route == Route.BYPASS_CHN || config.route == Route.BYPASS_LAN_CHN) {
|
||||
val reject = ConfigUtils.getRejectList(getContext)
|
||||
val blackList = ConfigUtils.getBlackList(getContext)
|
||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
||||
|
||||
@@ -344,7 +344,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
def startDnsDaemon() {
|
||||
val ipv6 = if (config.isIpv6) "" else "reject = ::/0;"
|
||||
val conf = {
|
||||
if (config.route == Route.BYPASS_CHN) {
|
||||
if (config.route == Route.BYPASS_CHN || config.route == Route.BYPASS_LAN_CHN) {
|
||||
val reject = ConfigUtils.getRejectList(getContext)
|
||||
val blackList = ConfigUtils.getBlackList(getContext)
|
||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
||||
@@ -401,7 +401,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
if (config.route == Route.ALL) {
|
||||
if (config.route == Route.ALL || config.route == Route.BYPASS_CHN) {
|
||||
builder.addRoute("0.0.0.0", 0)
|
||||
} else {
|
||||
val privateList = getResources.getStringArray(R.array.bypass_private_route)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.github.shadowsocks.utils
|
||||
|
||||
import android.util.Log
|
||||
|
||||
/**
|
||||
* @author chentaov5@gmail.com
|
||||
*/
|
||||
object IOUtils {
|
||||
|
||||
val TAG = "IOUtils"
|
||||
|
||||
def autoClose[R <: {def close() : Unit}, T](in: R)(fun: => T): T = {
|
||||
try {
|
||||
fun
|
||||
} finally if (in ne null)
|
||||
try {
|
||||
in.close()
|
||||
} catch {
|
||||
case e: Exception => Log.d(TAG, e.getMessage, e)
|
||||
}
|
||||
}
|
||||
|
||||
def inSafe[T](fun: => T): Option[T] = {
|
||||
var res: Option[T] = None
|
||||
try {
|
||||
res = Some(fun)
|
||||
} catch {
|
||||
case e: Exception => Log.d(TAG, e.getMessage, e)
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.github.shadowsocks.utils
|
||||
|
||||
import java.io.{BufferedReader, FileInputStream, InputStreamReader}
|
||||
|
||||
import android.content.Context
|
||||
import com.github.shadowsocks.utils.IOUtils._
|
||||
|
||||
/**
|
||||
* @author chentaov5@gmail.com
|
||||
*/
|
||||
object ProcessUtils {
|
||||
|
||||
def getCurrentProcessName: String = {
|
||||
inSafe {
|
||||
val inputStream = new FileInputStream("/proc/self/cmdline")
|
||||
val reader = new BufferedReader(new InputStreamReader(inputStream))
|
||||
autoClose(reader) {
|
||||
val sb = new StringBuilder
|
||||
var c: Int = 0
|
||||
while({c = reader.read(); c > 0})
|
||||
sb.append(c.asInstanceOf[Char])
|
||||
sb.toString()
|
||||
}
|
||||
} match {
|
||||
case Some(name: String) => name
|
||||
case None => ""
|
||||
}
|
||||
}
|
||||
|
||||
def inShadowsocks[A](context: Context)(fun: => A): Unit = {
|
||||
if (context != null && getCurrentProcessName.equals(context.getPackageName)) fun
|
||||
}
|
||||
|
||||
|
||||
def inVpn[A](context: Context)(fun: => A): Unit = {
|
||||
if (context != null && getCurrentProcessName.equals(context.getPackageName + ":vpn")) fun
|
||||
}
|
||||
|
||||
|
||||
def inNat[A](context: Context)(fun: => A): Unit = {
|
||||
if (context != null && getCurrentProcessName.equals(context.getPackageName + ":nat")) fun
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user