Only restore services when permitted

This commit is contained in:
Mygod
2021-10-29 23:13:24 -04:00
parent e48810d944
commit 1b329558dc
7 changed files with 36 additions and 21 deletions

View File

@@ -48,6 +48,7 @@ class App : Application() {
// alternative to PreferenceManager.getDefaultSharedPreferencesName(this) // alternative to PreferenceManager.getDefaultSharedPreferencesName(this)
deviceStorage.moveSharedPreferencesFrom(this, PreferenceManager(this).sharedPreferencesName) deviceStorage.moveSharedPreferencesFrom(this, PreferenceManager(this).sharedPreferencesName)
deviceStorage.moveDatabaseFrom(this, AppDatabase.DB_NAME) deviceStorage.moveDatabaseFrom(this, AppDatabase.DB_NAME)
BootReceiver.migrateIfNecessary()
} else deviceStorage = this } else deviceStorage = this
Services.init { this } Services.init { this }
@@ -92,7 +93,6 @@ class App : Application() {
}) })
EBegFragment.init() EBegFragment.init()
if (DhcpWorkaround.shouldEnable) DhcpWorkaround.enable(true) if (DhcpWorkaround.shouldEnable) DhcpWorkaround.enable(true)
BootReceiver.init()
} }
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {

View File

@@ -5,13 +5,11 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build
import android.os.Parcelable import android.os.Parcelable
import android.widget.Toast import androidx.annotation.RequiresApi
import be.mygod.librootkotlinx.toByteArray import be.mygod.librootkotlinx.toByteArray
import be.mygod.librootkotlinx.toParcelable import be.mygod.librootkotlinx.toParcelable
import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.util.readableMessage
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import timber.log.Timber import timber.log.Timber
import java.io.DataInputStream import java.io.DataInputStream
@@ -30,6 +28,7 @@ class BootReceiver : BroadcastReceiver() {
set(value) = app.packageManager.setComponentEnabledSetting(componentName, set(value) = app.packageManager.setComponentEnabledSetting(componentName,
if (value) PackageManager.COMPONENT_ENABLED_STATE_ENABLED if (value) PackageManager.COMPONENT_ENABLED_STATE_ENABLED
else PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP) else PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP)
private val userEnabled get() = app.pref.getBoolean(KEY, false)
fun onUserSettingUpdated(shouldStart: Boolean) { fun onUserSettingUpdated(shouldStart: Boolean) {
enabled = shouldStart && try { enabled = shouldStart && try {
config config
@@ -39,7 +38,7 @@ class BootReceiver : BroadcastReceiver() {
}?.startables?.isEmpty() == false }?.startables?.isEmpty() == false
} }
private fun onConfigUpdated(isNotEmpty: Boolean) { private fun onConfigUpdated(isNotEmpty: Boolean) {
enabled = isNotEmpty && app.pref.getBoolean(KEY, false) enabled = isNotEmpty && userEnabled
} }
private const val FILENAME = "bootconfig" private const val FILENAME = "bootconfig"
@@ -75,16 +74,19 @@ class BootReceiver : BroadcastReceiver() {
inline fun <reified T> add(value: Startable) = add(T::class.java.name, value) inline fun <reified T> add(value: Startable) = add(T::class.java.name, value)
inline fun <reified T> delete() = delete(T::class.java.name) inline fun <reified T> delete() = delete(T::class.java.name)
fun init() { @RequiresApi(24)
if (Build.VERSION.SDK_INT >= 24) { fun migrateIfNecessary() {
val oldFile = File(app.noBackupFilesDir, FILENAME) val oldFile = File(app.noBackupFilesDir, FILENAME)
if (oldFile.canRead()) try { if (oldFile.canRead()) try {
if (!configFile.exists()) oldFile.copyTo(configFile) if (!configFile.exists()) oldFile.copyTo(configFile)
if (!oldFile.delete()) oldFile.deleteOnExit() if (!oldFile.delete()) oldFile.deleteOnExit()
} catch (e: Exception) { } catch (e: Exception) {
Timber.w(e) Timber.w(e)
}
} }
}
private var started = false
private fun startIfNecessary() {
if (started) return
val config = try { val config = try {
synchronized(BootReceiver) { config } synchronized(BootReceiver) { config }
} catch (e: Exception) { } catch (e: Exception) {
@@ -93,12 +95,11 @@ class BootReceiver : BroadcastReceiver() {
} }
if (config == null || config.startables.isEmpty()) { if (config == null || config.startables.isEmpty()) {
enabled = false enabled = false
} else for (startable in config.startables.values) try { } else for (startable in config.startables.values) startable.start(app)
startable.start(app) started = true
} catch (e: IllegalStateException) { // ForegroundServiceStartNotAllowedException }
Timber.w(e) fun startIfEnabled() {
Toast.makeText(app, e.readableMessage, Toast.LENGTH_LONG).show() if (started && userEnabled) startIfNecessary()
}
} }
} }
@@ -109,5 +110,11 @@ class BootReceiver : BroadcastReceiver() {
@Parcelize @Parcelize
private data class Config(var startables: MutableMap<String, Startable> = mutableMapOf()) : Parcelable private data class Config(var startables: MutableMap<String, Startable> = mutableMapOf()) : Parcelable
override fun onReceive(context: Context, intent: Intent) { } override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
Intent.ACTION_BOOT_COMPLETED, Intent.ACTION_LOCKED_BOOT_COMPLETED, Intent.ACTION_MY_PACKAGE_REPLACED -> {
if (userEnabled) startIfNecessary() else enabled = false
}
}
}
} }

View File

@@ -68,6 +68,7 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService(), CoroutineScope {
override fun onBind(intent: Intent?) = binder override fun onBind(intent: Intent?) = binder
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
BootReceiver.startIfEnabled()
if (binder.iface != null) return START_STICKY if (binder.iface != null) return START_STICKY
binder.iface = "" binder.iface = ""
updateNotification() // show invisible foreground notification to avoid being killed updateNotification() // show invisible foreground notification to avoid being killed

View File

@@ -62,6 +62,7 @@ class MainActivity : AppCompatActivity(), NavigationBarView.OnItemSelectedListen
SmartSnackbar.Register(binding.fragmentHolder) SmartSnackbar.Register(binding.fragmentHolder)
WifiDoubleLock.ActivityListener(this) WifiDoubleLock.ActivityListener(this)
lifecycleScope.launch { lifecycleScope.launch {
BootReceiver.startIfEnabled()
repeatOnLifecycle(Lifecycle.State.STARTED) { repeatOnLifecycle(Lifecycle.State.STARTED) {
onAppUpdateAvailable(null) onAppUpdateAvailable(null)
try { try {

View File

@@ -354,6 +354,7 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
* startService Step 1 * startService Step 1
*/ */
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
BootReceiver.startIfEnabled()
if (status != Status.IDLE) return START_NOT_STICKY if (status != Status.IDLE) return START_NOT_STICKY
val channel = channel ?: return START_NOT_STICKY.also { stopSelf() } val channel = channel ?: return START_NOT_STICKY.also { stopSelf() }
status = Status.STARTING status = Status.STARTING

View File

@@ -111,6 +111,7 @@ class TetheringService : IpNeighbourMonitoringService(), TetheringManager.Tether
override fun onBind(intent: Intent?) = binder override fun onBind(intent: Intent?) = binder
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
BootReceiver.startIfEnabled()
// call this first just in case we are shutting down immediately // call this first just in case we are shutting down immediately
if (Build.VERSION.SDK_INT >= 26) updateNotification() if (Build.VERSION.SDK_INT >= 26) updateNotification()
launch { launch {

View File

@@ -1,12 +1,14 @@
package be.mygod.vpnhotspot.util package be.mygod.vpnhotspot.util
import android.content.ComponentName import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection import android.content.ServiceConnection
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.service.quicksettings.Tile import android.service.quicksettings.Tile
import android.service.quicksettings.TileService import android.service.quicksettings.TileService
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import be.mygod.vpnhotspot.BootReceiver
@RequiresApi(24) @RequiresApi(24)
abstract class KillableTileService : TileService(), ServiceConnection { abstract class KillableTileService : TileService(), ServiceConnection {
@@ -25,4 +27,6 @@ abstract class KillableTileService : TileService(), ServiceConnection {
onClick() onClick()
} }
} }
override fun onBind(intent: Intent?) = super.onBind(intent).also { BootReceiver.startIfEnabled() }
} }