Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bae0b9e746 | ||
|
|
15262343f4 | ||
|
|
be31a0ce82 | ||
|
|
0b0b6137b8 | ||
|
|
156b0c27f5 | ||
|
|
ca99596270 | ||
|
|
e22ffa8601 | ||
|
|
24233f104a | ||
|
|
01306d527d | ||
|
|
5547b42283 | ||
|
|
3dba966355 | ||
|
|
c9a7dc8deb | ||
|
|
4df7634fae | ||
|
|
97dd8fa15e |
@@ -20,7 +20,7 @@ resolvers += "madeye private releases" at "http://madeye-maven-repository.google
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"dnsjava" % "dnsjava" % "2.1.5",
|
||||
"org.scalaj" %% "scalaj-http" % "0.3.10",
|
||||
"com.github.kevinsawicki" % "http-request" % "5.6",
|
||||
"commons-net" % "commons-net" % "3.3",
|
||||
"com.google.zxing" % "android-integration" % "2.2"
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.github.shadowsocks"
|
||||
android:versionCode="88"
|
||||
android:versionName="2.5.0">
|
||||
android:versionCode="90"
|
||||
android:versionName="2.5.2">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<string name="forward_stop">后台服务已停止。</string>
|
||||
<string name="service_failed">无法连接远程服务器</string>
|
||||
<string name="stop">停止服务</string>
|
||||
<string name="stopping">正在关闭...</string>
|
||||
<string name="vpn_error">后台服务启动失败:\"%s\"。</string>
|
||||
<string name="ok_iknow">确定</string>
|
||||
<string name="port_alert">端口号应大于1024</string>
|
||||
@@ -68,6 +69,9 @@
|
||||
<string name="flushing">刷新中...</string>
|
||||
<string name="add_profile">添加配置文件</string>
|
||||
|
||||
<string name="enable_nat">启用 NAT 模式.</string>
|
||||
<string name="disable_nat">禁用 NAT 模式.</string>
|
||||
|
||||
<string name="udp_dns">UDP 转发</string>
|
||||
<string name="udp_dns_summary">由远程服务器转发 UDP 协议的数据包</string>
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -57,7 +57,10 @@
|
||||
<string name="forward_stop">Shadowsocks stopped.</string>
|
||||
<string name="service_failed">Failed to connect the remote server</string>
|
||||
<string name="stop">Stop the service</string>
|
||||
<string name="stopping">Shutting down...</string>
|
||||
<string name="vpn_error">Error: \"%s\".</string>
|
||||
<string name="enable_nat">Turn on NAT mode.</string>
|
||||
<string name="disable_nat">Turn off NAT mode.</string>
|
||||
|
||||
<!-- alert category -->
|
||||
<string name="ok_iknow">OK</string>
|
||||
|
||||
@@ -46,7 +46,6 @@ import android.content.pm.PackageManager
|
||||
import android.graphics.{Bitmap, PixelFormat}
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Message
|
||||
import android.preference.PreferenceManager
|
||||
import android.view.View
|
||||
import android.view.View.OnClickListener
|
||||
@@ -62,7 +61,10 @@ import com.nostra13.universalimageloader.core.{DisplayImageOptions, ImageLoader,
|
||||
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer
|
||||
import com.github.shadowsocks.utils.{Utils, Scheme, Key}
|
||||
|
||||
case class ProxiedApp(uid: Int, name: String, var proxied: Boolean)
|
||||
import scala.concurrent.ops._
|
||||
import scala.language.implicitConversions
|
||||
|
||||
case class ProxiedApp(uid: Int, name: String, packageName: String, var proxied: Boolean)
|
||||
|
||||
class ObjectArrayTools[T <: AnyRef](a: Array[T]) {
|
||||
def binarySearch(key: T) = {
|
||||
@@ -74,7 +76,7 @@ case class ListEntry(box: CheckBox, text: TextView, icon: ImageView)
|
||||
|
||||
object AppManager {
|
||||
|
||||
implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]) = new ObjectArrayTools(a)
|
||||
implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]): ObjectArrayTools[T] = new ObjectArrayTools(a)
|
||||
|
||||
def getProxiedApps(context: Context, proxiedAppString: String): Array[ProxiedApp] = {
|
||||
|
||||
@@ -86,13 +88,13 @@ object AppManager {
|
||||
val appList = packageManager.getInstalledApplications(0)
|
||||
|
||||
appList.filter(_.uid >= 10000).map {
|
||||
case a => {
|
||||
case a =>
|
||||
val uid = a.uid
|
||||
val userName = uid.toString
|
||||
val name = packageManager.getApplicationLabel(a).toString
|
||||
val packageName = a.packageName
|
||||
val proxied = proxiedApps.binarySearch(userName) >= 0
|
||||
new ProxiedApp(uid, packageName, proxied)
|
||||
}
|
||||
new ProxiedApp(uid, name, packageName, proxied)
|
||||
}.toArray
|
||||
}
|
||||
}
|
||||
@@ -103,7 +105,7 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
|
||||
val MSG_LOAD_FINISH = 2
|
||||
val STUB = android.R.drawable.sym_def_app_icon
|
||||
|
||||
implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]) = new ObjectArrayTools(a)
|
||||
implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]): ObjectArrayTools[T] = new ObjectArrayTools(a)
|
||||
|
||||
var apps: Array[ProxiedApp] = null
|
||||
var appListView: ListView = null
|
||||
@@ -129,8 +131,9 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
|
||||
val uid = a.uid
|
||||
val userName = uid.toString
|
||||
val name = packageManager.getApplicationLabel(a).toString
|
||||
val packageName = a.packageName
|
||||
val proxied = (proxiedApps binarySearch userName) >= 0
|
||||
new ProxiedApp(uid, name, proxied)
|
||||
new ProxiedApp(uid, name, packageName, proxied)
|
||||
}.toArray
|
||||
}
|
||||
|
||||
@@ -175,7 +178,7 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
|
||||
.cacheOnDisc()
|
||||
.displayer(new FadeInBitmapDisplayer(300))
|
||||
.build()
|
||||
ImageLoader.getInstance().displayImage(Scheme.APP + app.uid, entry.icon, options)
|
||||
ImageLoader.getInstance().displayImage(Scheme.APP + app.packageName, entry.icon, options)
|
||||
|
||||
entry.text.setText(app.name)
|
||||
val box: CheckBox = entry.box
|
||||
@@ -243,18 +246,17 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
|
||||
}
|
||||
})
|
||||
bypassSwitch.setChecked(prefs.getBoolean(Key.isBypassApps, false))
|
||||
|
||||
appListView = findViewById(R.id.applistview).asInstanceOf[ListView]
|
||||
}
|
||||
|
||||
protected override def onResume() {
|
||||
super.onResume()
|
||||
new Thread {
|
||||
override def run() {
|
||||
handler.post(loadStartRunnable)
|
||||
appListView = findViewById(R.id.applistview).asInstanceOf[ListView]
|
||||
if (!appsLoaded) loadApps()
|
||||
handler.post(loadFinishRunnable)
|
||||
}
|
||||
}.start()
|
||||
spawn {
|
||||
handler.post(loadStartRunnable)
|
||||
if (!appsLoaded) loadApps()
|
||||
handler.post(loadFinishRunnable)
|
||||
}
|
||||
}
|
||||
|
||||
def saveAppSettings(context: Context) {
|
||||
@@ -319,8 +321,8 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
|
||||
}
|
||||
|
||||
override def getStreamFromOtherSource(imageUri: String, extra: AnyRef): InputStream = {
|
||||
val uid = imageUri.substring(Scheme.APP.length).toInt
|
||||
val drawable = Utils.getAppIcon(getBaseContext, uid)
|
||||
val packageName = imageUri.substring(Scheme.APP.length)
|
||||
val drawable = Utils.getAppIcon(getBaseContext, packageName)
|
||||
val bitmap = Utils.drawableToBitmap(drawable)
|
||||
|
||||
val os = new ByteArrayOutputStream()
|
||||
|
||||
@@ -81,11 +81,15 @@ trait BaseService {
|
||||
}
|
||||
|
||||
override def stop() {
|
||||
stopRunner()
|
||||
if (state != State.CONNECTING && state != State.STOPPING) {
|
||||
stopRunner()
|
||||
}
|
||||
}
|
||||
|
||||
override def start(config: Config) {
|
||||
startRunner(config)
|
||||
if (state != State.CONNECTING && state != State.STOPPING) {
|
||||
startRunner(config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ import android.net.{Uri, VpnService}
|
||||
import android.os._
|
||||
import android.preference._
|
||||
import android.util.{DisplayMetrics, Log}
|
||||
import android.view.View.OnLongClickListener
|
||||
import android.view._
|
||||
import android.webkit.{WebView, WebViewClient}
|
||||
import android.widget._
|
||||
@@ -340,7 +341,7 @@ class Shadowsocks
|
||||
Process.killProcess(pid_nat)
|
||||
Process.killProcess(pid_vpn)
|
||||
} catch {
|
||||
case e: Throwable => Log.e(Shadowsocks.TAG, "unable to kill " + task, e)
|
||||
case e: Throwable => Log.e(Shadowsocks.TAG, "unable to kill " + task)
|
||||
}
|
||||
cmd.append("rm -f %s%s-nat.pid".format(Path.BASE, task))
|
||||
cmd.append("rm -f %s%s-nat.conf".format(Path.BASE, task))
|
||||
@@ -499,13 +500,30 @@ class Shadowsocks
|
||||
getActionBar.setDisplayShowTitleEnabled(false)
|
||||
getActionBar.setDisplayShowCustomEnabled(true)
|
||||
getActionBar.setIcon(R.drawable.ic_stat_shadowsocks)
|
||||
title.setOnLongClickListener(new OnLongClickListener {
|
||||
override def onLongClick(v: View): Boolean = {
|
||||
if (Utils.isLollipopOrAbove && bgService != null
|
||||
&& (bgService.getState == State.INIT || bgService.getState == State.STOPPED)) {
|
||||
val natEnabled = status.getBoolean(Key.isNAT, false)
|
||||
status.edit().putBoolean(Key.isNAT, !natEnabled).commit()
|
||||
if (!natEnabled) {
|
||||
Toast.makeText(getBaseContext, R.string.enable_nat, Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
Toast.makeText(getBaseContext, R.string.disable_nat, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Register broadcast receiver
|
||||
registerReceiver(preferenceReceiver, new IntentFilter(Action.UPDATE_PREFS))
|
||||
|
||||
// Bind to the service
|
||||
spawn {
|
||||
val isRoot = Console.isRoot
|
||||
val isRoot = (!Utils.isLollipopOrAbove || status.getBoolean(Key.isNAT, false)) && Console.isRoot
|
||||
handler.post(new Runnable {
|
||||
override def run() {
|
||||
status.edit.putBoolean(Key.isRoot, isRoot).commit()
|
||||
@@ -1006,6 +1024,11 @@ class Shadowsocks
|
||||
.show()
|
||||
}
|
||||
setPreferenceEnabled(enabled = true)
|
||||
case State.STOPPING =>
|
||||
if (progressDialog == null) {
|
||||
progressDialog = ProgressDialog
|
||||
.show(Shadowsocks.this, "", getString(R.string.stopping), true, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ package com.github.shadowsocks
|
||||
|
||||
import java.io.File
|
||||
import java.lang.reflect.{InvocationTargetException, Method}
|
||||
import java.net.InetAddress
|
||||
import java.util
|
||||
|
||||
import android.app.{Notification, NotificationManager, PendingIntent, Service}
|
||||
import android.content._
|
||||
@@ -48,7 +50,8 @@ import android.content.pm.{PackageInfo, PackageManager}
|
||||
import android.net.{Network, ConnectivityManager}
|
||||
import android.os._
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import android.util.Log
|
||||
import android.util.{SparseArray, Log}
|
||||
import android.widget.Toast
|
||||
import com.github.shadowsocks.aidl.Config
|
||||
import com.github.shadowsocks.utils._
|
||||
import com.google.android.gms.analytics.HitBuilders
|
||||
@@ -70,9 +73,12 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
private val mStartForegroundSignature = Array[Class[_]](classOf[Int], classOf[Notification])
|
||||
private val mStopForegroundSignature = Array[Class[_]](classOf[Boolean])
|
||||
private val mSetForegroundSignature = Array[Class[_]](classOf[Boolean])
|
||||
private val mSetForegroundArgs = new Array[AnyRef](1)
|
||||
private val mStartForegroundArgs = new Array[AnyRef](2)
|
||||
private val mStopForegroundArgs = new Array[AnyRef](1)
|
||||
|
||||
var closeReceiver: BroadcastReceiver = null
|
||||
var conReceiver: BroadcastReceiver = null
|
||||
var connReceiver: BroadcastReceiver = null
|
||||
var notificationManager: NotificationManager = null
|
||||
var config: Config = null
|
||||
var apps: Array[ProxiedApp] = null
|
||||
@@ -81,51 +87,98 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
private var mSetForeground: Method = null
|
||||
private var mStartForeground: Method = null
|
||||
private var mStopForeground: Method = null
|
||||
private var mSetForegroundArgs = new Array[AnyRef](1)
|
||||
private var mStartForegroundArgs = new Array[AnyRef](2)
|
||||
private var mStopForegroundArgs = new Array[AnyRef](1)
|
||||
|
||||
private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
|
||||
|
||||
def setDnsForAllNetwork(dns: String) {
|
||||
private val dnsAddressCache = new SparseArray[String]
|
||||
|
||||
def getNetId(network: Network): Int = {
|
||||
network.getClass.getDeclaredField("netId").get(network).asInstanceOf[Int]
|
||||
}
|
||||
|
||||
def restoreDnsForAllNetwork() {
|
||||
val manager = getSystemService(Context.CONNECTIVITY_SERVICE).asInstanceOf[ConnectivityManager]
|
||||
val networks = manager.getAllNetworks
|
||||
val cmdBuf = new ArrayBuffer[String]()
|
||||
networks.foreach(network => {
|
||||
val networkInfo = manager.getNetworkInfo(network)
|
||||
if (networkInfo.isAvailable) {
|
||||
val netId = network.getClass.getDeclaredField("netId").get(network).asInstanceOf[Int]
|
||||
cmdBuf.append("ndc resolver setnetdns %d \"\" %s".format(netId, dns))
|
||||
val netId = getNetId(network)
|
||||
val oldDns = dnsAddressCache.get(netId)
|
||||
if (oldDns != null) {
|
||||
cmdBuf.append("ndc resolver setnetdns %d \"\" %s".format(netId, oldDns))
|
||||
dnsAddressCache.remove(netId)
|
||||
}
|
||||
})
|
||||
Console.runRootCommand(cmdBuf.toArray)
|
||||
if (cmdBuf.nonEmpty) Console.runRootCommand(cmdBuf.toArray)
|
||||
}
|
||||
|
||||
def setupDns() = {
|
||||
def setDnsForAllNetwork(dns: String) {
|
||||
val manager = getSystemService(Context.CONNECTIVITY_SERVICE).asInstanceOf[ConnectivityManager]
|
||||
val networks = manager.getAllNetworks
|
||||
if (networks == null) return
|
||||
|
||||
val cmdBuf = new ArrayBuffer[String]()
|
||||
networks.foreach(network => {
|
||||
val networkInfo = manager.getNetworkInfo(network)
|
||||
if (networkInfo == null) return
|
||||
if (networkInfo.isConnected) {
|
||||
val netId = getNetId(network)
|
||||
val curDnsList = manager.getLinkProperties(network).getDnsServers
|
||||
if (curDnsList != null) {
|
||||
import scala.collection.JavaConverters._
|
||||
val curDns = curDnsList.asScala.map(ip => ip.getHostAddress).mkString(" ")
|
||||
if (curDns != dns) {
|
||||
dnsAddressCache.put(netId, curDns)
|
||||
cmdBuf.append("ndc resolver setnetdns %d \"\" %s".format(netId, dns))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
if (cmdBuf.nonEmpty) Console.runRootCommand(cmdBuf.toArray)
|
||||
}
|
||||
|
||||
def setupDns() {
|
||||
setDnsForAllNetwork("127.0.0.1")
|
||||
}
|
||||
|
||||
def resetDns() = {
|
||||
setDnsForAllNetwork("8.8.8.8 208.67.222.222 114.114.114.114")
|
||||
restoreDnsForAllNetwork()
|
||||
}
|
||||
|
||||
def flushDns() {
|
||||
if (Utils.isLollipopOrAbove) {
|
||||
val manager = getSystemService(Context.CONNECTIVITY_SERVICE).asInstanceOf[ConnectivityManager]
|
||||
val networks = manager.getAllNetworks
|
||||
val cmdBuf = new ArrayBuffer[String]()
|
||||
networks.foreach(network => {
|
||||
val networkInfo = manager.getNetworkInfo(network)
|
||||
if (networkInfo.isAvailable) {
|
||||
val netId = network.getClass.getDeclaredField("netId").get(network).asInstanceOf[Int]
|
||||
cmdBuf.append("ndc resolver flushnet %d".format(netId))
|
||||
}
|
||||
})
|
||||
Console.runRootCommand(cmdBuf.toArray)
|
||||
} else {
|
||||
Console.runRootCommand(Array("ndc resolver flushdefaultif", "ndc resolver flushif wlan0"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def destroyConnectionReceiver() {
|
||||
if (conReceiver != null) {
|
||||
unregisterReceiver(conReceiver)
|
||||
conReceiver = null
|
||||
if (connReceiver != null) {
|
||||
unregisterReceiver(connReceiver)
|
||||
connReceiver = null
|
||||
}
|
||||
resetDns()
|
||||
}
|
||||
|
||||
def initConnectionReceiver() {
|
||||
setupDns()
|
||||
val filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
|
||||
conReceiver = new BroadcastReceiver {
|
||||
connReceiver = new BroadcastReceiver {
|
||||
override def onReceive(context: Context, intent: Intent) = {
|
||||
setupDns()
|
||||
}
|
||||
}
|
||||
registerReceiver(conReceiver, filter)
|
||||
registerReceiver(connReceiver, filter)
|
||||
}
|
||||
|
||||
def startShadowsocksDaemon() {
|
||||
@@ -265,7 +318,6 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
startRedsocksDaemon()
|
||||
startShadowsocksDaemon()
|
||||
setupIptables()
|
||||
flushDNS()
|
||||
|
||||
true
|
||||
}
|
||||
@@ -353,7 +405,7 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
cmd.append("kill -9 %d".format(pid))
|
||||
Process.killProcess(pid)
|
||||
} catch {
|
||||
case e: Throwable => Log.e(TAG, "unable to kill " + task, e)
|
||||
case e: Throwable => Log.e(TAG, "unable to kill " + task)
|
||||
}
|
||||
cmd.append("rm -f %s%s-nat.pid".format(Path.BASE, task))
|
||||
cmd.append("rm -f %s%s-nat.conf".format(Path.BASE, task))
|
||||
@@ -363,10 +415,6 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
Console.runRootCommand(Utils.getIptables + " -t nat -F OUTPUT")
|
||||
}
|
||||
|
||||
def flushDNS() {
|
||||
Console.runRootCommand(Array("ndc resolver flushdefaultif", "ndc resolver flushif wlan0"))
|
||||
}
|
||||
|
||||
def setupIptables() = {
|
||||
val init_sb = new ArrayBuffer[String]
|
||||
val http_sb = new ArrayBuffer[String]
|
||||
@@ -453,20 +501,21 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
|
||||
config = c
|
||||
|
||||
// register connection receiver
|
||||
if (Utils.isLollipopOrAbove) initConnectionReceiver()
|
||||
|
||||
// register close receiver
|
||||
val filter = new IntentFilter()
|
||||
filter.addAction(Intent.ACTION_SHUTDOWN)
|
||||
filter.addAction(Action.CLOSE)
|
||||
closeReceiver = new BroadcastReceiver() {
|
||||
def onReceive(p1: Context, p2: Intent) {
|
||||
Toast.makeText(p1, R.string.stopping, Toast.LENGTH_SHORT).show()
|
||||
stopRunner()
|
||||
}
|
||||
}
|
||||
registerReceiver(closeReceiver, filter)
|
||||
|
||||
// register connection receiver
|
||||
if (Utils.isLollipopOrAbove) initConnectionReceiver()
|
||||
|
||||
// send event
|
||||
application.tracker.send(new HitBuilders.EventBuilder()
|
||||
.setCategory(TAG)
|
||||
@@ -492,6 +541,7 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
|
||||
if (config != null) {
|
||||
|
||||
// Clean up
|
||||
killProcesses()
|
||||
|
||||
var resolved: Boolean = false
|
||||
@@ -508,6 +558,11 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
}
|
||||
|
||||
if (resolved && handleConnection) {
|
||||
|
||||
// Set DNS
|
||||
if (Utils.isLollipopOrAbove) setupDns()
|
||||
flushDns()
|
||||
|
||||
notifyForegroundAlert(getString(R.string.forward_success),
|
||||
getString(R.string.service_running).format(config.profileName))
|
||||
changeState(State.CONNECTED)
|
||||
@@ -521,6 +576,9 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
|
||||
override def stopRunner() {
|
||||
|
||||
// channge the state
|
||||
changeState(State.STOPPING)
|
||||
|
||||
// clean up recevier
|
||||
if (closeReceiver != null) {
|
||||
unregisterReceiver(closeReceiver)
|
||||
|
||||
@@ -50,7 +50,8 @@ import com.github.shadowsocks.aidl.IShadowsocksService
|
||||
|
||||
class ShadowsocksRunnerActivity extends Activity {
|
||||
|
||||
lazy val settings = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
private lazy val settings = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
private lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE)
|
||||
|
||||
val handler = new Handler()
|
||||
val connection = new ServiceConnection {
|
||||
@@ -72,10 +73,10 @@ class ShadowsocksRunnerActivity extends Activity {
|
||||
|
||||
def isVpnEnabled: Boolean = {
|
||||
if (vpnEnabled < 0) {
|
||||
vpnEnabled = if (!Console.isRoot) {
|
||||
1
|
||||
} else {
|
||||
vpnEnabled = if ((!Utils.isLollipopOrAbove || status.getBoolean(Key.isNAT, false)) && Console.isRoot) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
if (vpnEnabled == 1) true else false
|
||||
|
||||
@@ -47,6 +47,7 @@ import android.content.pm.{PackageInfo, PackageManager}
|
||||
import android.net.VpnService
|
||||
import android.os._
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.github.shadowsocks.aidl.Config
|
||||
import com.github.shadowsocks.utils._
|
||||
import com.google.android.gms.analytics.HitBuilders
|
||||
@@ -190,7 +191,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
val pkgSet: mutable.HashSet[String] = new mutable.HashSet[String]
|
||||
for (app <- apps) {
|
||||
if (app.proxied) {
|
||||
pkgSet.add(app.name)
|
||||
pkgSet.add(app.packageName)
|
||||
}
|
||||
}
|
||||
for (pkg <- pkgSet) {
|
||||
@@ -367,7 +368,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
val pid = scala.io.Source.fromFile(Path.BASE + task + "-vpn.pid").mkString.trim.toInt
|
||||
Process.killProcess(pid)
|
||||
} catch {
|
||||
case e: Throwable => Log.e(TAG, "unable to kill " + task, e)
|
||||
case e: Throwable => Log.e(TAG, "unable to kill " + task)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,6 +397,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
filter.addAction(Intent.ACTION_SHUTDOWN)
|
||||
receiver = new BroadcastReceiver {
|
||||
def onReceive(p1: Context, p2: Intent) {
|
||||
Toast.makeText(p1, R.string.stopping, Toast.LENGTH_SHORT)
|
||||
stopRunner()
|
||||
}
|
||||
}
|
||||
@@ -448,7 +450,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
override def stopRunner() {
|
||||
|
||||
// channge the state
|
||||
changeState(State.STOPPED)
|
||||
changeState(State.STOPPING)
|
||||
|
||||
// send event
|
||||
application.tracker.send(new HitBuilders.EventBuilder()
|
||||
@@ -476,6 +478,9 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
unregisterReceiver(receiver)
|
||||
receiver = null
|
||||
}
|
||||
|
||||
// channge the state
|
||||
changeState(State.STOPPED)
|
||||
}
|
||||
|
||||
override def stopBackgroundService() {
|
||||
|
||||
@@ -42,7 +42,7 @@ package com.github.shadowsocks.utils
|
||||
import android.content.{SharedPreferences, Context}
|
||||
import com.github.shadowsocks.ShadowsocksApplication
|
||||
import com.google.android.gms.tagmanager.Container
|
||||
import scalaj.http.{HttpOptions, Http}
|
||||
import com.github.kevinsawicki.http.HttpRequest
|
||||
import com.github.shadowsocks.aidl.Config
|
||||
|
||||
object ConfigUtils {
|
||||
@@ -183,12 +183,12 @@ object ConfigUtils {
|
||||
def getPublicConfig(context: Context, container: Container, config: Config): Config = {
|
||||
val url = container.getString("proxy_url")
|
||||
val sig = Utils.getSignature(context)
|
||||
val list = Http
|
||||
val list = HttpRequest
|
||||
.post(url)
|
||||
.params("sig" -> sig)
|
||||
.option(HttpOptions.connTimeout(1000))
|
||||
.option(HttpOptions.readTimeout(5000))
|
||||
.asString
|
||||
.connectTimeout(2000)
|
||||
.readTimeout(2000)
|
||||
.send("sig="+sig)
|
||||
.body
|
||||
val proxies = util.Random.shuffle(list.split('|').toSeq).toSeq
|
||||
val proxy = proxies(0).split(':')
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ object Key {
|
||||
|
||||
val proxied = "Proxyed"
|
||||
|
||||
val isNAT = "isNAT"
|
||||
val isRoot = "isRoot"
|
||||
val status = "status"
|
||||
val proxyedApps = "proxyedApps"
|
||||
@@ -101,7 +102,8 @@ object State {
|
||||
val INIT = 0
|
||||
val CONNECTING = 1
|
||||
val CONNECTED = 2
|
||||
val STOPPED = 3
|
||||
val STOPPING = 3
|
||||
val STOPPED = 4
|
||||
def isAvailable(state: Int): Boolean = state != CONNECTED && state != CONNECTING
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ object Utils {
|
||||
val DEFAULT_ROOT: String = "/system/bin/su"
|
||||
val ALTERNATIVE_ROOT: String = "/system/xbin/su"
|
||||
val DEFAULT_IPTABLES: String = "/system/bin/iptables"
|
||||
val ALTERNATIVE_IPTABLES: String = "/data/data/com.github.shadowsocks/iptables"
|
||||
val ALTERNATIVE_IPTABLES: String = "iptables"
|
||||
val TIME_OUT: Int = -99
|
||||
var initialized: Boolean = false
|
||||
var hasRedirectSupport: Int = -1
|
||||
@@ -181,20 +181,24 @@ object Utils {
|
||||
}
|
||||
|
||||
def resolve(host: String, addrType: Int): Option[String] = {
|
||||
val lookup = new Lookup(host, addrType)
|
||||
val resolver = new SimpleResolver("114.114.114.114")
|
||||
resolver.setTimeout(5)
|
||||
lookup.setResolver(resolver)
|
||||
val result = lookup.run()
|
||||
if (result == null) return None
|
||||
val records = scala.util.Random.shuffle(result.toList)
|
||||
for (r <- records) {
|
||||
addrType match {
|
||||
case Type.A =>
|
||||
return Some(r.asInstanceOf[ARecord].getAddress.getHostAddress)
|
||||
case Type.AAAA =>
|
||||
return Some(r.asInstanceOf[AAAARecord].getAddress.getHostAddress)
|
||||
try {
|
||||
val lookup = new Lookup(host, addrType)
|
||||
val resolver = new SimpleResolver("114.114.114.114")
|
||||
resolver.setTimeout(5)
|
||||
lookup.setResolver(resolver)
|
||||
val result = lookup.run()
|
||||
if (result == null) return None
|
||||
val records = scala.util.Random.shuffle(result.toList)
|
||||
for (r <- records) {
|
||||
addrType match {
|
||||
case Type.A =>
|
||||
return Some(r.asInstanceOf[ARecord].getAddress.getHostAddress)
|
||||
case Type.AAAA =>
|
||||
return Some(r.asInstanceOf[AAAARecord].getAddress.getHostAddress)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
case e: Exception => None
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -332,6 +336,16 @@ object Utils {
|
||||
bitmap
|
||||
}
|
||||
|
||||
def getAppIcon(c: Context, packageName: String): Drawable = {
|
||||
val pm: PackageManager = c.getPackageManager
|
||||
val icon: Drawable = c.getResources.getDrawable(android.R.drawable.sym_def_app_icon)
|
||||
try {
|
||||
pm.getApplicationIcon(packageName)
|
||||
} catch {
|
||||
case e: PackageManager.NameNotFoundException => icon
|
||||
}
|
||||
}
|
||||
|
||||
def getAppIcon(c: Context, uid: Int): Drawable = {
|
||||
val pm: PackageManager = c.getPackageManager
|
||||
val icon: Drawable = c.getResources.getDrawable(android.R.drawable.sym_def_app_icon)
|
||||
|
||||
Reference in New Issue
Block a user