Commit ff0ddd59 authored by Max Lv's avatar Max Lv

force VpnService as a foreground service

parent bf3933bf
...@@ -69,25 +69,13 @@ class ShadowsocksNatService extends Service with BaseService { ...@@ -69,25 +69,13 @@ class ShadowsocksNatService extends Service with BaseService {
val CMD_IPTABLES_DNAT_ADD_SOCKS = " -t nat -A OUTPUT -p tcp " + val CMD_IPTABLES_DNAT_ADD_SOCKS = " -t nat -A OUTPUT -p tcp " +
"-j DNAT --to-destination 127.0.0.1:8123" "-j DNAT --to-destination 127.0.0.1:8123"
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 lockReceiver: BroadcastReceiver = null var lockReceiver: BroadcastReceiver = null
var closeReceiver: BroadcastReceiver = null var closeReceiver: BroadcastReceiver = null
var connReceiver: BroadcastReceiver = null var connReceiver: BroadcastReceiver = null
var notificationManager: NotificationManager = null
var config: Config = null var config: Config = null
var apps: Array[ProxiedApp] = null var apps: Array[ProxiedApp] = null
val myUid = Process.myUid() val myUid = Process.myUid()
private var mSetForeground: Method = null
private var mStartForeground: Method = null
private var mStopForeground: Method = null
private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication] private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
private val dnsAddressCache = new SparseArray[String] private val dnsAddressCache = new SparseArray[String]
...@@ -321,17 +309,6 @@ class ShadowsocksNatService extends Service with BaseService { ...@@ -321,17 +309,6 @@ class ShadowsocksNatService extends Service with BaseService {
true true
} }
def invokeMethod(method: Method, args: Array[AnyRef]) {
try {
method.invoke(this, mStartForegroundArgs: _*)
} catch {
case e: InvocationTargetException =>
Log.w(TAG, "Unable to invoke method", e)
case e: IllegalAccessException =>
Log.w(TAG, "Unable to invoke method", e)
}
}
def notifyForegroundAlert(title: String, info: String, visible: Boolean) { def notifyForegroundAlert(title: String, info: String, visible: Boolean) {
val openIntent = new Intent(this, classOf[Shadowsocks]) val openIntent = new Intent(this, classOf[Shadowsocks])
openIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) openIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
...@@ -355,7 +332,7 @@ class ShadowsocksNatService extends Service with BaseService { ...@@ -355,7 +332,7 @@ class ShadowsocksNatService extends Service with BaseService {
else else
builder.setPriority(NotificationCompat.PRIORITY_MIN) builder.setPriority(NotificationCompat.PRIORITY_MIN)
startForegroundCompat(1, builder.build) startForeground(1, builder.build)
} }
def onBind(intent: Intent): IBinder = { def onBind(intent: Intent): IBinder = {
...@@ -369,29 +346,7 @@ class ShadowsocksNatService extends Service with BaseService { ...@@ -369,29 +346,7 @@ class ShadowsocksNatService extends Service with BaseService {
override def onCreate() { override def onCreate() {
super.onCreate() super.onCreate()
ConfigUtils.refresh(this) ConfigUtils.refresh(this)
notificationManager = this
.getSystemService(Context.NOTIFICATION_SERVICE)
.asInstanceOf[NotificationManager]
try {
mStartForeground = getClass.getMethod("startForeground", mStartForegroundSignature: _*)
mStopForeground = getClass.getMethod("stopForeground", mStopForegroundSignature: _*)
} catch {
case e: NoSuchMethodException =>
mStartForeground = {
mStopForeground = null
mStopForeground
}
}
try {
mSetForeground = getClass.getMethod("setForeground", mSetForegroundSignature: _*)
} catch {
case e: NoSuchMethodException =>
throw new IllegalStateException(
"OS doesn't have Service.startForeground OR Service.setForeground!")
}
} }
def killProcesses() { def killProcesses() {
...@@ -462,44 +417,6 @@ class ShadowsocksNatService extends Service with BaseService { ...@@ -462,44 +417,6 @@ class ShadowsocksNatService extends Service with BaseService {
Console.runRootCommand(http_sb.toArray) Console.runRootCommand(http_sb.toArray)
} }
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
def startForegroundCompat(id: Int, notification: Notification) {
if (mStartForeground != null) {
mStartForegroundArgs(0) = int2Integer(id)
mStartForegroundArgs(1) = notification
invokeMethod(mStartForeground, mStartForegroundArgs)
return
}
mSetForegroundArgs(0) = boolean2Boolean(x = true)
invokeMethod(mSetForeground, mSetForegroundArgs)
notificationManager.notify(id, notification)
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
def stopForegroundCompat(id: Int) {
if (mStopForeground != null) {
mStopForegroundArgs(0) = boolean2Boolean(x = true)
try {
mStopForeground.invoke(this, mStopForegroundArgs: _*)
} catch {
case e: InvocationTargetException =>
Log.w(TAG, "Unable to invoke stopForeground", e)
case e: IllegalAccessException =>
Log.w(TAG, "Unable to invoke stopForeground", e)
}
return
}
notificationManager.cancel(id)
mSetForegroundArgs(0) = boolean2Boolean(x = false)
invokeMethod(mSetForeground, mSetForegroundArgs)
}
override def startRunner(c: Config) { override def startRunner(c: Config) {
config = c config = c
...@@ -627,7 +544,7 @@ class ShadowsocksNatService extends Service with BaseService { ...@@ -627,7 +544,7 @@ class ShadowsocksNatService extends Service with BaseService {
stopSelf() stopSelf()
} }
stopForegroundCompat(1) stopForeground(true)
// change the state // change the state
changeState(State.STOPPED) changeState(State.STOPPED)
......
...@@ -47,6 +47,7 @@ import android.content._ ...@@ -47,6 +47,7 @@ import android.content._
import android.content.pm.{PackageInfo, PackageManager} import android.content.pm.{PackageInfo, PackageManager}
import android.net.VpnService import android.net.VpnService
import android.os._ import android.os._
import android.support.v4.app.NotificationCompat
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import com.github.shadowsocks.aidl.Config import com.github.shadowsocks.aidl.Config
...@@ -67,7 +68,6 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -67,7 +68,6 @@ class ShadowsocksVpnService extends VpnService with BaseService {
val PRIVATE_VLAN = "26.26.26.%s" val PRIVATE_VLAN = "26.26.26.%s"
val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s" val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s"
var conn: ParcelFileDescriptor = null var conn: ParcelFileDescriptor = null
var notificationManager: NotificationManager = null
var receiver: BroadcastReceiver = null var receiver: BroadcastReceiver = null
var apps: Array[ProxiedApp] = null var apps: Array[ProxiedApp] = null
var config: Config = null var config: Config = null
...@@ -104,15 +104,34 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -104,15 +104,34 @@ class ShadowsocksVpnService extends VpnService with BaseService {
null null
} }
override def onCreate() { def notifyForegroundAlert(title: String, info: String, visible: Boolean) {
val openIntent = new Intent(this, classOf[Shadowsocks])
super.onCreate() val contentIntent = PendingIntent.getActivity(this, 0, openIntent, 0)
val closeIntent = new Intent(Action.CLOSE)
val actionIntent = PendingIntent.getBroadcast(this, 0, closeIntent, 0)
val builder = new NotificationCompat.Builder(this)
ConfigUtils.refresh(this) builder
.setWhen(0)
.setTicker(title)
.setContentTitle(getString(R.string.app_name))
.setContentText(info)
.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_stat_shadowsocks)
.addAction(android.R.drawable.ic_menu_close_clear_cancel, getString(R.string.stop),
actionIntent)
if (visible)
builder.setPriority(NotificationCompat.PRIORITY_DEFAULT)
else
builder.setPriority(NotificationCompat.PRIORITY_MIN)
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) startForeground(1, builder.build)
.asInstanceOf[NotificationManager] }
override def onCreate() {
super.onCreate()
ConfigUtils.refresh(this)
} }
override def onRevoke() { override def onRevoke() {
...@@ -126,6 +145,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -126,6 +145,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
vpnThread = null vpnThread = null
} }
stopForeground(true)
// channge the state // channge the state
changeState(State.STOPPING) changeState(State.STOPPING)
...@@ -248,6 +269,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -248,6 +269,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
} }
if (resolved && handleConnection) { if (resolved && handleConnection) {
notifyForegroundAlert(getString(R.string.forward_success),
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), false)
changeState(State.CONNECTED) changeState(State.CONNECTED)
} else { } else {
changeState(State.STOPPED, getString(R.string.service_failed)) changeState(State.STOPPED, getString(R.string.service_failed))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment