Commit 85c23a12 authored by Mygod's avatar Mygod

Avoid resolving every plugin in :bg

parent 6e4dd864
......@@ -242,7 +242,7 @@ object BaseService {
File(Core.deviceStorage.noBackupFilesDir, "stat_main"),
File(configRoot, CONFIG_FILE),
if (udpFallback == null) "-u" else null)
check(udpFallback?.pluginPath == null) { "UDP fallback cannot have plugins" }
check(udpFallback?.plugin == null) { "UDP fallback cannot have plugins" }
udpFallback?.start(this,
File(Core.deviceStorage.noBackupFilesDir, "stat_udp"),
File(configRoot, CONFIG_FILE_UDP),
......
......@@ -47,8 +47,7 @@ import java.security.MessageDigest
class ProxyInstance(val profile: Profile, private val route: String = profile.route) {
private var configFile: File? = null
var trafficMonitor: TrafficMonitor? = null
private val plugin = PluginConfiguration(profile.plugin ?: "").selectedOptions
val pluginPath by lazy { PluginManager.init(plugin) }
val plugin by lazy { PluginManager.init(PluginConfiguration(profile.plugin ?: "")) }
private var scheduleConfigUpdate = false
suspend fun init(service: BaseService.Interface, hosts: HostsFile) {
......@@ -115,7 +114,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
this.configFile = configFile
val config = profile.toJson()
if (pluginPath != null) config.put("plugin", pluginPath).put("plugin_opts", plugin.toString())
plugin?.let { (path, opts) -> config.put("plugin", path).put("plugin_opts", opts.toString()) }
configFile.writeText(config.toString())
val cmd = service.buildAdditionalArguments(arrayListOf(
......
......@@ -301,7 +301,7 @@ data class Profile(
.encodedAuthority("$auth@$wrappedHost:$remotePort")
val configuration = PluginConfiguration(plugin ?: "")
if (configuration.selected.isNotEmpty()) {
builder.appendQueryParameter(Key.plugin, configuration.selectedOptions.toString(false))
builder.appendQueryParameter(Key.plugin, configuration.getOptions().toString(false))
}
if (!name.isNullOrEmpty()) builder.fragment(name)
return builder.build()
......@@ -315,7 +315,7 @@ data class Profile(
put("password", password)
put("method", method)
if (profiles == null) return@apply
PluginConfiguration(plugin ?: "").selectedOptions.also {
PluginConfiguration(plugin ?: "").getOptions().also {
if (it.id.isNotEmpty()) {
put("plugin", it.id)
put("plugin_opts", it.toString())
......
......@@ -50,15 +50,15 @@ class PluginConfiguration(val pluginsOptions: Map<String, PluginOptions>, val se
} else PluginOptions(line)
})
fun getOptions(id: String): PluginOptions = if (id.isEmpty()) PluginOptions() else {
pluginsOptions[id] ?: PluginOptions(id, PluginManager.fetchPlugins().lookup[id]?.defaultConfig)
}
val selectedOptions: PluginOptions get() = getOptions(selected)
fun getOptions(
id: String = selected,
defaultConfig: () -> String? = { PluginManager.fetchPlugins().lookup[id]?.defaultConfig }
) = if (id.isEmpty()) PluginOptions() else pluginsOptions[id] ?: PluginOptions(id, defaultConfig())
override fun toString(): String {
val result = LinkedList<PluginOptions>()
for ((id, opt) in pluginsOptions) if (id == this.selected) result.addFirst(opt) else result.addLast(opt)
if (!pluginsOptions.contains(selected)) result.addFirst(selectedOptions)
if (!pluginsOptions.contains(selected)) result.addFirst(getOptions())
return result.joinToString("\n") { it.toString(false) }
}
}
......@@ -24,13 +24,12 @@ import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.ContentResolver
import android.content.Intent
import android.content.pm.ComponentInfo
import android.content.pm.PackageManager
import android.content.pm.ProviderInfo
import android.content.pm.Signature
import android.content.res.Resources
import android.database.Cursor
import android.net.Uri
import android.os.Bundle
import android.system.Os
import android.util.Base64
import android.util.Log
......@@ -123,30 +122,31 @@ object PluginManager {
// the following parts are meant to be used by :bg
@Throws(Throwable::class)
fun init(options: PluginOptions): String? {
if (options.id.isEmpty()) return null
fun init(configuration: PluginConfiguration): Pair<String, PluginOptions>? {
if (configuration.selected.isEmpty()) return null
var throwable: Throwable? = null
try {
val path = initNative(options)
if (path != null) return path
val result = initNative(configuration)
if (result != null) return result
} catch (t: Throwable) {
if (throwable == null) throwable = t else printLog(t)
}
// add other plugin types here
throw throwable ?: PluginNotFoundException(options.id)
throw throwable ?: PluginNotFoundException(configuration.selected)
}
private fun initNative(options: PluginOptions): String? {
val providers = app.packageManager.queryIntentContentProviders(
Intent(PluginContract.ACTION_NATIVE_PLUGIN, buildUri(options.id)), PackageManager.GET_META_DATA)
private fun initNative(configuration: PluginConfiguration): Pair<String, PluginOptions>? {
val providers = app.packageManager.queryIntentContentProviders(Intent(PluginContract.ACTION_NATIVE_PLUGIN,
buildUri(configuration.selected)), PackageManager.GET_META_DATA)
if (providers.isEmpty()) return null
val provider = providers.single().providerInfo
val options = configuration.getOptions { provider.loadString(PluginContract.METADATA_KEY_DEFAULT_CONFIG) }
var failure: Throwable? = null
try {
initNativeFaster(provider)?.also { return it }
initNativeFaster(provider)?.also { return it to options }
} catch (t: Throwable) {
Crashlytics.log(Log.WARN, TAG, "Initializing native plugin faster mode failed")
failure = t
......@@ -156,9 +156,8 @@ object PluginManager {
scheme(ContentResolver.SCHEME_CONTENT)
authority(provider.authority)
}.build()
val cr = app.contentResolver
try {
return initNativeFast(cr, options, uri)
return initNativeFast(app.contentResolver, options, uri)?.let { it to options }
} catch (t: Throwable) {
Crashlytics.log(Log.WARN, TAG, "Initializing native plugin fast mode failed")
failure?.also { t.addSuppressed(it) }
......@@ -166,7 +165,7 @@ object PluginManager {
}
try {
return initNativeSlow(cr, options, uri)
return initNativeSlow(app.contentResolver, options, uri)?.let { it to options }
} catch (t: Throwable) {
failure?.also { t.addSuppressed(it) }
throw t
......@@ -174,9 +173,7 @@ object PluginManager {
}
private fun initNativeFaster(provider: ProviderInfo): String? {
return provider.metaData.loadString(PluginContract.METADATA_KEY_EXECUTABLE_PATH) {
app.packageManager.getResourcesForApplication(provider.applicationInfo)
}?.let { relativePath ->
return provider.loadString(PluginContract.METADATA_KEY_EXECUTABLE_PATH)?.let { relativePath ->
File(provider.applicationInfo.nativeLibraryDir).resolve(relativePath).apply {
check(canExecute())
}.absolutePath
......@@ -220,9 +217,9 @@ object PluginManager {
return File(pluginDir, options.id).absolutePath
}
fun Bundle.loadString(key: String, resources: () -> Resources) = when (val value = get(key)) {
fun ComponentInfo.loadString(key: String) = when (val value = metaData.get(key)) {
is String -> value
is Int -> resources().getString(value)
is Int -> app.packageManager.getResourcesForApplication(applicationInfo).getString(value)
null -> null
else -> error("meta-data $key has invalid type ${value.javaClass}")
}
......
......@@ -30,15 +30,16 @@ import com.github.shadowsocks.utils.signaturesCompat
abstract class ResolvedPlugin(protected val resolveInfo: ResolveInfo) : Plugin() {
protected abstract val componentInfo: ComponentInfo
private val resources by lazy { app.packageManager.getResourcesForApplication(componentInfo.applicationInfo) }
override val id by lazy { componentInfo.metaData.loadString(PluginContract.METADATA_KEY_ID) { resources }!! }
override val id by lazy { componentInfo.loadString(PluginContract.METADATA_KEY_ID)!! }
override val idAliases: Array<String> by lazy {
when (val value = componentInfo.metaData.get(PluginContract.METADATA_KEY_ID_ALIASES)) {
is String -> arrayOf(value)
is Int -> when (resources.getResourceTypeName(value)) {
"string" -> arrayOf(resources.getString(value))
else -> resources.getStringArray(value)
is Int -> app.packageManager.getResourcesForApplication(componentInfo.applicationInfo).run {
when (getResourceTypeName(value)) {
"string" -> arrayOf(getString(value))
else -> getStringArray(value)
}
}
null -> emptyArray()
else -> error("unknown type for plugin meta-data idAliases")
......@@ -46,9 +47,7 @@ abstract class ResolvedPlugin(protected val resolveInfo: ResolveInfo) : Plugin()
}
override val label: CharSequence get() = resolveInfo.loadLabel(app.packageManager)
override val icon: Drawable get() = resolveInfo.loadIcon(app.packageManager)
override val defaultConfig by lazy {
componentInfo.metaData.loadString(PluginContract.METADATA_KEY_DEFAULT_CONFIG) { resources }
}
override val defaultConfig by lazy { componentInfo.loadString(PluginContract.METADATA_KEY_DEFAULT_CONFIG) }
override val packageName: String get() = componentInfo.packageName
override val trusted by lazy {
Core.getPackageInfo(packageName).signaturesCompat.any(PluginManager.trustedSignatures::contains)
......
......@@ -132,7 +132,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
plugin.value = pluginConfiguration.selected
plugin.init()
pluginConfigure.isEnabled = pluginConfiguration.selected.isNotEmpty()
pluginConfigure.text = pluginConfiguration.selectedOptions.toString()
pluginConfigure.text = pluginConfiguration.getOptions().toString()
}
private fun showPluginEditor() {
......@@ -196,7 +196,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
PluginContract.ACTION_CONFIGURE)
if (intent.resolveActivity(requireContext().packageManager) == null) showPluginEditor() else {
startActivityForResult(intent
.putExtra(PluginContract.EXTRA_OPTIONS, pluginConfiguration.selectedOptions.toString()),
.putExtra(PluginContract.EXTRA_OPTIONS, pluginConfiguration.getOptions().toString()),
REQUEST_CODE_PLUGIN_CONFIGURE)
}
}
......@@ -216,7 +216,7 @@ class ProfileConfigFragment : PreferenceFragmentCompat(),
DataStore.plugin = pluginConfiguration.toString()
DataStore.dirty = true
pluginConfigure.isEnabled = selected !is NoPlugin
pluginConfigure.text = pluginConfiguration.selectedOptions.toString()
pluginConfigure.text = pluginConfiguration.getOptions().toString()
if (!selected.trusted) Snackbar.make(view!!, R.string.plugin_untrusted, Snackbar.LENGTH_LONG).show()
}
REQUEST_CODE_PLUGIN_CONFIGURE -> when (resultCode) {
......
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