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 {
val CMD_IPTABLES_DNAT_ADD_SOCKS = " -t nat -A OUTPUT -p tcp " +
"-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 closeReceiver: BroadcastReceiver = null
var connReceiver: BroadcastReceiver = null
var notificationManager: NotificationManager = null
var config: Config = null
var apps: Array[ProxiedApp] = null
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 val dnsAddressCache = new SparseArray[String]
......@@ -321,17 +309,6 @@ class ShadowsocksNatService extends Service with BaseService {
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) {
val openIntent = new Intent(this, classOf[Shadowsocks])
openIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
......@@ -355,7 +332,7 @@ class ShadowsocksNatService extends Service with BaseService {
else
builder.setPriority(NotificationCompat.PRIORITY_MIN)
startForegroundCompat(1, builder.build)
startForeground(1, builder.build)
}
def onBind(intent: Intent): IBinder = {
......@@ -369,29 +346,7 @@ class ShadowsocksNatService extends Service with BaseService {
override def onCreate() {
super.onCreate()
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() {
......@@ -462,44 +417,6 @@ class ShadowsocksNatService extends Service with BaseService {
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) {
config = c
......@@ -627,7 +544,7 @@ class ShadowsocksNatService extends Service with BaseService {
stopSelf()
}
stopForegroundCompat(1)
stopForeground(true)
// change the state
changeState(State.STOPPED)
......
......@@ -47,6 +47,7 @@ import android.content._
import android.content.pm.{PackageInfo, PackageManager}
import android.net.VpnService
import android.os._
import android.support.v4.app.NotificationCompat
import android.util.Log
import android.widget.Toast
import com.github.shadowsocks.aidl.Config
......@@ -67,7 +68,6 @@ class ShadowsocksVpnService extends VpnService with BaseService {
val PRIVATE_VLAN = "26.26.26.%s"
val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s"
var conn: ParcelFileDescriptor = null
var notificationManager: NotificationManager = null
var receiver: BroadcastReceiver = null
var apps: Array[ProxiedApp] = null
var config: Config = null
......@@ -104,15 +104,34 @@ class ShadowsocksVpnService extends VpnService with BaseService {
null
}
override def onCreate() {
super.onCreate()
def notifyForegroundAlert(title: String, info: String, visible: Boolean) {
val openIntent = new Intent(this, classOf[Shadowsocks])
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)
.asInstanceOf[NotificationManager]
startForeground(1, builder.build)
}
override def onCreate() {
super.onCreate()
ConfigUtils.refresh(this)
}
override def onRevoke() {
......@@ -126,6 +145,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
vpnThread = null
}
stopForeground(true)
// channge the state
changeState(State.STOPPING)
......@@ -248,6 +269,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
}
if (resolved && handleConnection) {
notifyForegroundAlert(getString(R.string.forward_success),
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), false)
changeState(State.CONNECTED)
} else {
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