Commit 418ae215 authored by Mygod's avatar Mygod

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.
parent fdd8a112
......@@ -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)
}
......
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