Refrain from unregistering stateChanged callbacks too aggressively
This commit adds `startListeningForBandwidth` and `stopListeningForBandwidth` to save battery as well as keeping the listener for state changing alive.
This commit is contained in:
@@ -7,6 +7,8 @@ interface IShadowsocksService {
|
||||
String getProfileName();
|
||||
|
||||
oneway void registerCallback(IShadowsocksServiceCallback cb);
|
||||
oneway void startListeningForBandwidth(IShadowsocksServiceCallback cb);
|
||||
oneway void stopListeningForBandwidth(IShadowsocksServiceCallback cb);
|
||||
oneway void unregisterCallback(IShadowsocksServiceCallback cb);
|
||||
|
||||
oneway void use(in int profileId);
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.util.{Timer, TimerTask}
|
||||
import android.app.Service
|
||||
import android.content.{BroadcastReceiver, Context, Intent, IntentFilter}
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.{Handler, RemoteCallbackList}
|
||||
import android.os.{Handler, IBinder, RemoteCallbackList}
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
@@ -39,6 +39,7 @@ import com.github.shadowsocks.database.Profile
|
||||
import com.github.shadowsocks.utils._
|
||||
import okhttp3.{Dns, FormBody, OkHttpClient, Request}
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.util.Random
|
||||
|
||||
trait BaseService extends Service {
|
||||
@@ -54,7 +55,7 @@ trait BaseService extends Service {
|
||||
var trafficMonitorThread: TrafficMonitorThread = _
|
||||
|
||||
final val callbacks = new RemoteCallbackList[IShadowsocksServiceCallback]
|
||||
var callbacksCount: Int = _
|
||||
private final val bandwidthListeners = new mutable.HashSet[IBinder]() // the binder is the real identifier
|
||||
lazy val handler = new Handler(getMainLooper)
|
||||
lazy val restartHanlder = new Handler(getMainLooper)
|
||||
lazy val protectPath: String = getApplicationInfo.dataDir + "/protect_path"
|
||||
@@ -85,31 +86,29 @@ trait BaseService extends Service {
|
||||
|
||||
override def getProfileName: String = if (profile == null) null else profile.getName
|
||||
|
||||
override def unregisterCallback(cb: IShadowsocksServiceCallback) {
|
||||
if (cb != null && callbacks.unregister(cb)) {
|
||||
callbacksCount -= 1
|
||||
if (callbacksCount == 0 && timer != null) {
|
||||
timer.cancel()
|
||||
timer = null
|
||||
}
|
||||
}
|
||||
}
|
||||
override def registerCallback(cb: IShadowsocksServiceCallback): Unit = callbacks.register(cb)
|
||||
|
||||
override def registerCallback(cb: IShadowsocksServiceCallback) {
|
||||
if (cb != null && callbacks.register(cb)) {
|
||||
callbacksCount += 1
|
||||
if (callbacksCount != 0 && timer == null) {
|
||||
val task = new TimerTask {
|
||||
def run() {
|
||||
if (TrafficMonitor.updateRate()) updateTrafficRate()
|
||||
}
|
||||
}
|
||||
override def startListeningForBandwidth(cb: IShadowsocksServiceCallback): Unit =
|
||||
if (bandwidthListeners.add(cb.asBinder)){
|
||||
if (timer == null) {
|
||||
timer = new Timer(true)
|
||||
timer.schedule(task, 1000, 1000)
|
||||
timer.schedule(new TimerTask {
|
||||
def run(): Unit = if (TrafficMonitor.updateRate()) updateTrafficRate()
|
||||
}, 1000, 1000)
|
||||
}
|
||||
TrafficMonitor.updateRate()
|
||||
cb.trafficUpdated(TrafficMonitor.txRate, TrafficMonitor.rxRate, TrafficMonitor.txTotal, TrafficMonitor.rxTotal)
|
||||
}
|
||||
|
||||
override def stopListeningForBandwidth(cb: IShadowsocksServiceCallback): Unit =
|
||||
if (bandwidthListeners.remove(cb.asBinder) && bandwidthListeners.isEmpty) {
|
||||
timer.cancel()
|
||||
timer = null
|
||||
}
|
||||
|
||||
override def unregisterCallback(cb: IShadowsocksServiceCallback) {
|
||||
stopListeningForBandwidth(cb) // saves an RPC, and safer
|
||||
callbacks.unregister(cb)
|
||||
}
|
||||
|
||||
override def use(profileId: Int): Unit = synchronized(if (profileId < 0) stopRunner(stopService = true) else {
|
||||
@@ -258,7 +257,7 @@ trait BaseService extends Service {
|
||||
|
||||
def updateTrafficRate() {
|
||||
handler.post(() => {
|
||||
if (callbacksCount > 0) {
|
||||
if (bandwidthListeners.nonEmpty) {
|
||||
val txRate = TrafficMonitor.txRate
|
||||
val rxRate = TrafficMonitor.rxRate
|
||||
val txTotal = TrafficMonitor.txTotal
|
||||
@@ -266,7 +265,8 @@ trait BaseService extends Service {
|
||||
val n = callbacks.beginBroadcast()
|
||||
for (i <- 0 until n) {
|
||||
try {
|
||||
callbacks.getBroadcastItem(i).trafficUpdated(txRate, rxRate, txTotal, rxTotal)
|
||||
val item = callbacks.getBroadcastItem(i)
|
||||
if (bandwidthListeners.contains(item.asBinder)) item.trafficUpdated(txRate, rxRate, txTotal, rxTotal)
|
||||
} catch {
|
||||
case _: Exception => // Ignore
|
||||
}
|
||||
@@ -289,7 +289,7 @@ trait BaseService extends Service {
|
||||
protected def changeState(s: Int, msg: String = null) {
|
||||
val handler = new Handler(getMainLooper)
|
||||
handler.post(() => if (state != s || msg != null) {
|
||||
if (callbacksCount > 0) {
|
||||
if (callbacks.getRegisteredCallbackCount > 0) {
|
||||
val n = callbacks.beginBroadcast()
|
||||
for (i <- 0 until n) {
|
||||
try {
|
||||
|
||||
@@ -142,7 +142,9 @@ class MainActivity extends Activity with ServiceBoundContext with Drawer.OnDrawe
|
||||
override def onServiceConnected() {
|
||||
// Update the UI
|
||||
if (fab != null) fab.setEnabled(true)
|
||||
updateState()
|
||||
Log.d(TAG, "bgService " + bgService.getState)
|
||||
callback.stateChanged(bgService.getState, null, null)
|
||||
state = bgService.getState
|
||||
if (Build.VERSION.SDK_INT >= 21 && app.isNatEnabled) {
|
||||
val snackbar = Snackbar.make(findViewById(R.id.snackbar), R.string.nat_deprecated, Snackbar.LENGTH_LONG)
|
||||
addDisableNatToSnackbar(snackbar)
|
||||
@@ -393,25 +395,14 @@ class MainActivity extends Activity with ServiceBoundContext with Drawer.OnDrawe
|
||||
}
|
||||
}
|
||||
|
||||
private def updateState() {
|
||||
if (bgService != null) {
|
||||
Log.d(TAG, "bgService " + bgService.getState)
|
||||
callback.stateChanged(bgService.getState, null, null)
|
||||
state = bgService.getState
|
||||
}
|
||||
}
|
||||
|
||||
protected override def onResume() {
|
||||
super.onResume()
|
||||
|
||||
app.refreshContainerHolder()
|
||||
|
||||
updateState()
|
||||
}
|
||||
|
||||
override def onStart() {
|
||||
super.onStart()
|
||||
registerCallback()
|
||||
setListeningForBandwidth(true)
|
||||
}
|
||||
|
||||
override def onBackPressed(): Unit =
|
||||
@@ -421,8 +412,8 @@ class MainActivity extends Activity with ServiceBoundContext with Drawer.OnDrawe
|
||||
} else super.onBackPressed()
|
||||
|
||||
override def onStop() {
|
||||
setListeningForBandwidth(false)
|
||||
super.onStop()
|
||||
unregisterCallback()
|
||||
}
|
||||
|
||||
override def onDestroy() {
|
||||
|
||||
@@ -35,7 +35,13 @@ trait ServiceBoundContext extends Context with IBinder.DeathRecipient {
|
||||
binder = service
|
||||
service.linkToDeath(ServiceBoundContext.this, 0)
|
||||
bgService = IShadowsocksService.Stub.asInterface(service)
|
||||
registerCallback()
|
||||
if (callback != null && !callbackRegistered) try {
|
||||
bgService.registerCallback(callback)
|
||||
callbackRegistered = true
|
||||
if (listeningForBandwidth) bgService.startListeningForBandwidth(callback)
|
||||
} catch {
|
||||
case _: RemoteException => // Nothing
|
||||
}
|
||||
ServiceBoundContext.this.onServiceConnected()
|
||||
}
|
||||
override def onServiceDisconnected(name: ComponentName) {
|
||||
@@ -46,17 +52,17 @@ trait ServiceBoundContext extends Context with IBinder.DeathRecipient {
|
||||
}
|
||||
}
|
||||
|
||||
def registerCallback(): Unit = if (bgService != null && callback != null && !callbackRegistered) try {
|
||||
bgService.registerCallback(callback)
|
||||
callbackRegistered = true
|
||||
} catch {
|
||||
case _: RemoteException => // Nothing
|
||||
def setListeningForBandwidth(value: Boolean) {
|
||||
if (listeningForBandwidth != value && bgService != null && callback != null)
|
||||
if (value) bgService.startListeningForBandwidth(callback) else bgService.stopListeningForBandwidth(callback)
|
||||
listeningForBandwidth = value
|
||||
}
|
||||
|
||||
def unregisterCallback() {
|
||||
private def unregisterCallback() {
|
||||
if (bgService != null && callback != null && callbackRegistered) try bgService.unregisterCallback(callback) catch {
|
||||
case _: RemoteException =>
|
||||
}
|
||||
listeningForBandwidth = false
|
||||
callbackRegistered = false
|
||||
}
|
||||
|
||||
@@ -67,6 +73,7 @@ trait ServiceBoundContext extends Context with IBinder.DeathRecipient {
|
||||
private var callback: IShadowsocksServiceCallback.Stub = _
|
||||
private var connection: ShadowsocksServiceConnection = _
|
||||
private var callbackRegistered: Boolean = _
|
||||
private var listeningForBandwidth: Boolean = _
|
||||
|
||||
// Variables
|
||||
var binder: IBinder = _
|
||||
|
||||
@@ -80,6 +80,7 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str
|
||||
case Intent.ACTION_SCREEN_ON =>
|
||||
setVisible(visible && Utils.isLollipopOrAbove && !keyGuard.inKeyguardRestrictedInputMode, forceShow)
|
||||
service.binder.registerCallback(callback)
|
||||
service.binder.startListeningForBandwidth(callback)
|
||||
callbackRegistered = true
|
||||
case Intent.ACTION_USER_PRESENT => setVisible(visible = true, forceShow = forceShow)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user