Implement direct boot awareness
To do direct boot, important files need to be moved to device storage (i.e. not as safe storage). The only thing sensitive is user credentials (server settings in each profile) and the config file passed to libss-*.so. In order to implement direct boot, at least the active profile has to be moved/copied to device storage. This commit keeps profile information (and temporary data used by ProfileConfigFragment) and Shadowsocks config in credential storage and move everything else to device storage. In order to make direct boot work, active profile is also copied into device storage and Shadowsocks config file is created in device storage during direct boot. Cleanup of those information is also implemented. Fixes #1457. NB: * `android:directBootAware` can't be used on application element. That seems to be used by system apps. * Works fine with multi-user; * Old GSM files are not migrated (see App.kt) to device storage.
This commit is contained in:
@@ -20,11 +20,15 @@
|
||||
|
||||
package com.github.shadowsocks.bg
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.*
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.RemoteCallbackList
|
||||
import android.support.v4.os.UserManagerCompat
|
||||
import android.text.TextUtils
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
@@ -66,6 +70,8 @@ object BaseService {
|
||||
const val STOPPING = 3
|
||||
const val STOPPED = 4
|
||||
|
||||
const val CONFIG_FILE = "shadowsocks.conf"
|
||||
|
||||
class Data internal constructor(private val service: Interface) {
|
||||
@Volatile var profile: Profile? = null
|
||||
@Volatile var state = STOPPED
|
||||
@@ -163,7 +169,8 @@ object BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun buildShadowsocksConfig() {
|
||||
internal var shadowsocksConfigFile: File? = null
|
||||
internal fun buildShadowsocksConfig(): File {
|
||||
val profile = profile!!
|
||||
val config = JSONObject()
|
||||
.put("server", profile.host)
|
||||
@@ -178,7 +185,13 @@ object BaseService {
|
||||
.put("plugin", Commandline.toString(service.buildAdditionalArguments(pluginCmd)))
|
||||
.put("plugin_opts", plugin.toString())
|
||||
}
|
||||
File(app.filesDir, "shadowsocks.json").bufferedWriter().use { it.write(config.toString()) }
|
||||
// sensitive Shadowsocks config is stored in
|
||||
val file = File((if (UserManagerCompat.isUserUnlocked(app)) app.filesDir else @TargetApi(24) {
|
||||
app.deviceContext.noBackupFilesDir // only API 24+ will be in locked state
|
||||
}), CONFIG_FILE)
|
||||
shadowsocksConfigFile = file
|
||||
file.writeText(config.toString())
|
||||
return file
|
||||
}
|
||||
|
||||
val aclFile: File? get() {
|
||||
@@ -228,14 +241,13 @@ object BaseService {
|
||||
|
||||
fun startNativeProcesses() {
|
||||
val data = data
|
||||
data.buildShadowsocksConfig()
|
||||
val cmd = buildAdditionalArguments(arrayListOf(
|
||||
File((this as Context).applicationInfo.nativeLibraryDir, Executable.SS_LOCAL).absolutePath,
|
||||
"-u",
|
||||
"-b", "127.0.0.1",
|
||||
"-l", DataStore.portProxy.toString(),
|
||||
"-t", "600",
|
||||
"-c", "shadowsocks.json"))
|
||||
"-c", data.buildShadowsocksConfig().absolutePath))
|
||||
|
||||
val acl = data.aclFile
|
||||
if (acl != null) {
|
||||
@@ -278,6 +290,9 @@ object BaseService {
|
||||
data.closeReceiverRegistered = false
|
||||
}
|
||||
|
||||
data.shadowsocksConfigFile?.delete() // remove old config possibly in device storage
|
||||
data.shadowsocksConfigFile = null
|
||||
|
||||
data.notification?.destroy()
|
||||
data.notification = null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user