Commit 93084f0e authored by Mygod's avatar Mygod

Ask for ROOT only when it's needed

parent ac98caa4
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
<string name="auto_connect_summary">随系统启动后台服务</string> <string name="auto_connect_summary">随系统启动后台服务</string>
<string name="forward_success">后台服务已开始运行。</string> <string name="forward_success">后台服务已开始运行。</string>
<string name="service_failed">无法连接远程服务器</string> <string name="service_failed">无法连接远程服务器</string>
<string name="nat_no_root">NAT 模式需要 ROOT 权限</string>
<string name="switch_to_vpn">切换到 VPN 模式</string>
<string name="stop">停止服务</string> <string name="stop">停止服务</string>
<string name="stopping">正在关闭……</string> <string name="stopping">正在关闭……</string>
<string name="vpn_error">后台服务启动失败:%s</string> <string name="vpn_error">后台服务启动失败:%s</string>
...@@ -52,14 +54,15 @@ ...@@ -52,14 +54,15 @@
<string name="about">关于</string> <string name="about">关于</string>
<string name="about_title">影梭(shadowsocks)%s</string> <string name="about_title">影梭(shadowsocks)%s</string>
<string name="flush_dnscache">刷新 DNS 缓存</string> <string name="flush_dnscache">刷新 DNS 缓存</string>
<string name="flush_dnscache_summary_disabled">需要 ROOT 权限</string> <string name="flush_dnscache_summary">只需在 NAT 模式下使用</string>
<string name="flush_dnscache_summary_root">只需在 NAT 模式下使用,需要 ROOT 权限</string>
<string name="flush_dnscache_no_root">在没有 ROOT 权限的情况下无法刷新 DNS 缓存</string>
<string name="flushing">刷新中……</string> <string name="flushing">刷新中……</string>
<string name="qrcode">二维码</string> <string name="qrcode">二维码</string>
<string name="add_profile">添加配置文件</string> <string name="add_profile">添加配置文件</string>
<string name="nat">NAT 模式 (仅限调试)</string> <string name="nat">NAT 模式 (仅限调试)</string>
<string name="nat_summary">从 VPN 模式切换为 NAT 模式</string> <string name="nat_summary">从 VPN 模式切换为 NAT 模式,需要 ROOT 权限</string>
<string name="nat_summary_no_root">NAT 模式已禁用,需要 ROOT 权限</string>
<string name="udp_dns">UDP 转发</string> <string name="udp_dns">UDP 转发</string>
<string name="udp_dns_summary">由远程服务器转发 UDP 协议的数据包</string> <string name="udp_dns_summary">由远程服务器转发 UDP 协议的数据包</string>
......
...@@ -10,8 +10,7 @@ ...@@ -10,8 +10,7 @@
<string name="profile">Profile</string> <string name="profile">Profile</string>
<string name="profile_summary">Switch to another profile or add new profiles</string> <string name="profile_summary">Switch to another profile or add new profiles</string>
<string name="nat">NAT mode (deprecated)</string> <string name="nat">NAT mode (deprecated)</string>
<string name="nat_summary">Use NAT mode instead of VPN mode</string> <string name="nat_summary">Use NAT mode instead of VPN mode. Requires ROOT permission.</string>
<string name="nat_summary_no_root">NAT mode is disabled without root</string>
<string name="stat">Network Traffic</string> <string name="stat">Network Traffic</string>
<string name="stat_summary">Sent: \t\t\t\t\t%3$s\t↑\t%1$s/s\nReceived: \t%4$s\t↓\t%2$s/s</string> <string name="stat_summary">Sent: \t\t\t\t\t%3$s\t↑\t%1$s/s\nReceived: \t%4$s\t↓\t%2$s/s</string>
<string name="stat_profiles">\n%1$s↑\t%2$s↓</string> <string name="stat_profiles">\n%1$s↑\t%2$s↓</string>
...@@ -61,6 +60,8 @@ ...@@ -61,6 +60,8 @@
<!-- notification category --> <!-- notification category -->
<string name="forward_success">Shadowsocks started.</string> <string name="forward_success">Shadowsocks started.</string>
<string name="service_failed">Failed to connect the remote server</string> <string name="service_failed">Failed to connect the remote server</string>
<string name="nat_no_root">NAT mode requires ROOT permission</string>
<string name="switch_to_vpn">Switch to VPN mode</string>
<string name="stop">Stop the service</string> <string name="stop">Stop the service</string>
<string name="stopping">Shutting down…</string> <string name="stopping">Shutting down…</string>
<string name="vpn_error">%s</string> <string name="vpn_error">%s</string>
...@@ -84,7 +85,9 @@ ...@@ -84,7 +85,9 @@
<string name="about_title">Shadowsocks %s</string> <string name="about_title">Shadowsocks %s</string>
<string name="qrcode">QR Code</string> <string name="qrcode">QR Code</string>
<string name="flush_dnscache">Flush DNS cache</string> <string name="flush_dnscache">Flush DNS cache</string>
<string name="flush_dnscache_summary_disabled">Requires ROOT permission</string> <string name="flush_dnscache_summary">Only useful in NAT mode</string>
<string name="flush_dnscache_summary_root">Only useful in NAT mode. Requires ROOT permission.</string>
<string name="flush_dnscache_no_root">Flush DNS cache cannot proceed without ROOT permission</string>
<string name="flushing">Flushing</string> <string name="flushing">Flushing</string>
<string name="add_profile">Add Profile</string> <string name="add_profile">Add Profile</string>
<string name="action_export">Export to Clipboard</string> <string name="action_export">Export to Clipboard</string>
......
...@@ -83,12 +83,14 @@ ...@@ -83,12 +83,14 @@
android:summary="@string/auto_connect_summary" android:summary="@string/auto_connect_summary"
android:title="@string/auto_connect"/> android:title="@string/auto_connect"/>
<com.github.shadowsocks.preferences.NatSwitchPreference android:key="isNAT" <SwitchPreference android:key="isNAT"
android:title="@string/nat" android:title="@string/nat"
android:summary="@string/nat_summary"/> android:summary="@string/nat_summary"/>
<Preference android:key="recovery" android:title="@string/recovery" <Preference android:key="recovery" android:title="@string/recovery"
android:summary="@string/recovery_summary"/> android:summary="@string/recovery_summary"/>
<Preference android:key="flush_dnscache" android:title="@string/flush_dnscache"/> <Preference android:key="flush_dnscache"
android:title="@string/flush_dnscache"
android:summary="@string/flush_dnscache_summary_root"/>
<Preference android:key="about" android:title="@string/about"/> <Preference android:key="about" android:title="@string/about"/>
</PreferenceCategory> </PreferenceCategory>
......
...@@ -58,8 +58,6 @@ import com.github.shadowsocks.utils.{Key, Utils} ...@@ -58,8 +58,6 @@ import com.github.shadowsocks.utils.{Key, Utils}
import scala.collection.JavaConversions._ import scala.collection.JavaConversions._
import scala.collection.mutable import scala.collection.mutable
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.language.implicitConversions import scala.language.implicitConversions
object AppManager { object AppManager {
...@@ -249,7 +247,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -249,7 +247,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
} }
def loadAppsAsync() { def loadAppsAsync() {
Future { ThrowableFuture {
while (!appsLoading) loadApps() while (!appsLoading) loadApps()
appsLoading = false appsLoading = false
handler.post(() => { handler.post(() => {
......
...@@ -65,8 +65,6 @@ import com.github.shadowsocks.utils._ ...@@ -65,8 +65,6 @@ import com.github.shadowsocks.utils._
import com.google.android.gms.ads.{AdRequest, AdSize, AdView} import com.google.android.gms.ads.{AdRequest, AdSize, AdView}
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
object Typefaces { object Typefaces {
def get(c: Context, assetPath: String): Typeface = { def get(c: Context, assetPath: String): Typeface = {
...@@ -182,8 +180,13 @@ class Shadowsocks ...@@ -182,8 +180,13 @@ class Shadowsocks
handler.postDelayed(() => fabProgressCircle.hide(), 1000) handler.postDelayed(() => fabProgressCircle.hide(), 1000)
fab.setEnabled(true) fab.setEnabled(true)
changeSwitch(checked = false) changeSwitch(checked = false)
if (m != null) Snackbar.make(findViewById(android.R.id.content), if (m != null) {
getString(R.string.vpn_error).formatLocal(Locale.ENGLISH, m), Snackbar.LENGTH_LONG).show val snackbar = Snackbar.make(findViewById(android.R.id.content),
getString(R.string.vpn_error).formatLocal(Locale.ENGLISH, m), Snackbar.LENGTH_LONG)
if (m == getString(R.string.nat_no_root)) snackbar.setAction(R.string.switch_to_vpn,
(_ => preferences.natSwitch.setChecked(false)): View.OnClickListener)
snackbar.show
}
setPreferenceEnabled(enabled = true) setPreferenceEnabled(enabled = true)
case State.STOPPING => case State.STOPPING =>
fab.setBackgroundTintList(greyTint) fab.setBackgroundTintList(greyTint)
...@@ -317,10 +320,10 @@ class Shadowsocks ...@@ -317,10 +320,10 @@ class Shadowsocks
cmd.append("chmod 666 %s%s-vpn.pid".formatLocal(Locale.ENGLISH, Path.BASE, task)) cmd.append("chmod 666 %s%s-vpn.pid".formatLocal(Locale.ENGLISH, Path.BASE, task))
} }
if (!ShadowsocksApplication.isVpnEnabled) { if (ShadowsocksApplication.isVpnEnabled) {
Console.runRootCommand(cmd.toArray)
} else {
Console.runCommand(cmd.toArray) Console.runCommand(cmd.toArray)
} else {
Console.runRootCommand(cmd.toArray)
} }
cmd.clear() cmd.clear()
...@@ -341,8 +344,7 @@ class Shadowsocks ...@@ -341,8 +344,7 @@ class Shadowsocks
cmd.append("rm -f %s%s-vpn.pid".formatLocal(Locale.ENGLISH, Path.BASE, task)) cmd.append("rm -f %s%s-vpn.pid".formatLocal(Locale.ENGLISH, Path.BASE, task))
cmd.append("rm -f %s%s-vpn.conf".formatLocal(Locale.ENGLISH, Path.BASE, task)) cmd.append("rm -f %s%s-vpn.conf".formatLocal(Locale.ENGLISH, Path.BASE, task))
} }
Console.runCommand(cmd.toArray) if (ShadowsocksApplication.isVpnEnabled) Console.runCommand(cmd.toArray) else {
if (!ShadowsocksApplication.isVpnEnabled) {
Console.runRootCommand(cmd.toArray) Console.runRootCommand(cmd.toArray)
Console.runRootCommand(Utils.getIptables + " -t nat -F OUTPUT") Console.runRootCommand(Utils.getIptables + " -t nat -F OUTPUT")
} }
...@@ -361,7 +363,7 @@ class Shadowsocks ...@@ -361,7 +363,7 @@ class Shadowsocks
} }
def prepareStartService() { def prepareStartService() {
Future { ThrowableFuture {
if (ShadowsocksApplication.isVpnEnabled) { if (ShadowsocksApplication.isVpnEnabled) {
val intent = VpnService.prepare(this) val intent = VpnService.prepare(this)
if (intent != null) { if (intent != null) {
...@@ -534,18 +536,6 @@ class Shadowsocks ...@@ -534,18 +536,6 @@ class Shadowsocks
handler.removeCallbacksAndMessages(null) handler.removeCallbacksAndMessages(null)
} }
def copyToSystem() {
val ab = new ArrayBuffer[String]
ab.append("mount -o rw,remount -t yaffs2 /dev/block/mtdblock3 /system")
for (executable <- Shadowsocks.EXECUTABLES) {
ab.append("cp %s%s /system/bin/".formatLocal(Locale.ENGLISH, Path.BASE, executable))
ab.append("chmod 755 /system/bin/" + executable)
ab.append("chown root:shell /system/bin/" + executable)
}
ab.append("mount -o ro,remount -t yaffs2 /dev/block/mtdblock3 /system")
Console.runRootCommand(ab.toArray)
}
def install() { def install() {
copyAssets(System.getABI) copyAssets(System.getABI)
...@@ -565,7 +555,7 @@ class Shadowsocks ...@@ -565,7 +555,7 @@ class Shadowsocks
def recovery() { def recovery() {
serviceStop() serviceStop()
val h = showProgress(R.string.recovering) val h = showProgress(R.string.recovering)
Future { ThrowableFuture {
reset() reset()
h.sendEmptyMessage(0) h.sendEmptyMessage(0)
} }
...@@ -573,8 +563,9 @@ class Shadowsocks ...@@ -573,8 +563,9 @@ class Shadowsocks
def flushDnsCache() { def flushDnsCache() {
val h = showProgress(R.string.flushing) val h = showProgress(R.string.flushing)
Future { ThrowableFuture {
Utils.toggleAirplaneMode(getBaseContext) if (!Utils.toggleAirplaneMode(getBaseContext)) h.post(() => Snackbar.make(findViewById(android.R.id.content),
R.string.flush_dnscache_no_root, Snackbar.LENGTH_LONG).show)
h.sendEmptyMessage(0) h.sendEmptyMessage(0)
} }
} }
...@@ -595,7 +586,7 @@ class Shadowsocks ...@@ -595,7 +586,7 @@ class Shadowsocks
def checkText(key: String): Boolean = { def checkText(key: String): Boolean = {
val text = ShadowsocksApplication.settings.getString(key, "") val text = ShadowsocksApplication.settings.getString(key, "")
if (text != null && text.length > 0) return true if (text != null && text.length > 0) return true
Snackbar.make(findViewById(android.R.id.content), getString(R.string.proxy_empty), Snackbar.LENGTH_LONG).show Snackbar.make(findViewById(android.R.id.content), R.string.proxy_empty, Snackbar.LENGTH_LONG).show
false false
} }
......
...@@ -46,7 +46,7 @@ import android.app.Application ...@@ -46,7 +46,7 @@ import android.app.Application
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.preference.PreferenceManager import android.preference.PreferenceManager
import com.github.shadowsocks.database.{DBHelper, ProfileManager} import com.github.shadowsocks.database.{DBHelper, ProfileManager}
import com.github.shadowsocks.utils.{Console, Key, Utils} import com.github.shadowsocks.utils.{Key, Utils}
import com.google.android.gms.analytics.{GoogleAnalytics, HitBuilders} import com.google.android.gms.analytics.{GoogleAnalytics, HitBuilders}
import com.google.android.gms.common.api.ResultCallback import com.google.android.gms.common.api.ResultCallback
import com.google.android.gms.tagmanager.{ContainerHolder, TagManager} import com.google.android.gms.tagmanager.{ContainerHolder, TagManager}
...@@ -60,8 +60,7 @@ object ShadowsocksApplication { ...@@ -60,8 +60,7 @@ object ShadowsocksApplication {
lazy val settings = PreferenceManager.getDefaultSharedPreferences(instance) lazy val settings = PreferenceManager.getDefaultSharedPreferences(instance)
lazy val profileManager = new ProfileManager(settings, dbHelper) lazy val profileManager = new ProfileManager(settings, dbHelper)
val isRoot = Console.isRoot def isVpnEnabled = !settings.getBoolean(Key.isNAT, false)
def isVpnEnabled = !(isRoot && settings.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove))
def getVersionName = try { def getVersionName = try {
instance.getPackageManager.getPackageInfo(instance.getPackageName, 0).versionName instance.getPackageManager.getPackageInfo(instance.getPackageName, 0).versionName
......
...@@ -55,8 +55,6 @@ import com.github.shadowsocks.utils._ ...@@ -55,8 +55,6 @@ import com.github.shadowsocks.utils._
import scala.collection.JavaConversions._ import scala.collection.JavaConversions._
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
class ShadowsocksNatService extends BaseService { class ShadowsocksNatService extends BaseService {
...@@ -144,7 +142,7 @@ class ShadowsocksNatService extends BaseService { ...@@ -144,7 +142,7 @@ class ShadowsocksNatService extends BaseService {
}) })
Console.runRootCommand(cmdBuf.toArray) Console.runRootCommand(cmdBuf.toArray)
} else { } else {
Console.runRootCommand(Array("ndc resolver flushdefaultif", "ndc resolver flushif wlan0")) Console.runRootCommand("ndc resolver flushdefaultif", "ndc resolver flushif wlan0")
} }
} }
...@@ -384,12 +382,17 @@ class ShadowsocksNatService extends BaseService { ...@@ -384,12 +382,17 @@ class ShadowsocksNatService extends BaseService {
} }
} }
} }
Console.runRootCommand(init_sb.toArray) Console.runRootCommand((init_sb ++ http_sb).toArray)
Console.runRootCommand(http_sb.toArray)
} }
override def startRunner(config: Config) { override def startRunner(config: Config) {
changeState(State.CONNECTING)
if (!Console.isRoot) {
changeState(State.STOPPED, getString(R.string.nat_no_root))
return
}
super.startRunner(config) super.startRunner(config)
// register close receiver // register close receiver
...@@ -404,10 +407,7 @@ class ShadowsocksNatService extends BaseService { ...@@ -404,10 +407,7 @@ class ShadowsocksNatService extends BaseService {
ShadowsocksApplication.track(TAG, "start") ShadowsocksApplication.track(TAG, "start")
changeState(State.CONNECTING) ThrowableFuture {
Future {
if (config.proxy == "198.199.101.152") { if (config.proxy == "198.199.101.152") {
val holder = ShadowsocksApplication.containerHolder val holder = ShadowsocksApplication.containerHolder
try { try {
...@@ -465,7 +465,7 @@ class ShadowsocksNatService extends BaseService { ...@@ -465,7 +465,7 @@ class ShadowsocksNatService extends BaseService {
closeReceiver = null closeReceiver = null
} }
notification.destroy() if (notification != null) notification.destroy()
ShadowsocksApplication.track(TAG, "stop") ShadowsocksApplication.track(TAG, "stop")
......
...@@ -14,6 +14,7 @@ import com.github.shadowsocks.utils.Key ...@@ -14,6 +14,7 @@ import com.github.shadowsocks.utils.Key
// TODO: Move related logic here // TODO: Move related logic here
class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChangeListener { class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChangeListener {
private lazy val activity = getActivity.asInstanceOf[Shadowsocks] private lazy val activity = getActivity.asInstanceOf[Shadowsocks]
lazy val natSwitch = findPreference(Key.isNAT).asInstanceOf[SwitchPreference]
private var isProxyApps: SwitchPreference = _ private var isProxyApps: SwitchPreference = _
...@@ -35,10 +36,8 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan ...@@ -35,10 +36,8 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
}) })
val flush = findPreference("flush_dnscache") val flush = findPreference("flush_dnscache")
if (Build.VERSION.SDK_INT >= 17 && !ShadowsocksApplication.isRoot) { if (Build.VERSION.SDK_INT < 17) flush.setSummary(R.string.flush_dnscache_summary)
flush.setEnabled(false) flush.setOnPreferenceClickListener(_ => {
flush.setSummary(R.string.flush_dnscache_summary_disabled)
} else flush.setOnPreferenceClickListener((preference: Preference) => {
ShadowsocksApplication.track(Shadowsocks.TAG, "flush_dnscache") ShadowsocksApplication.track(Shadowsocks.TAG, "flush_dnscache")
activity.flushDnsCache() activity.flushDnsCache()
true true
...@@ -73,12 +72,10 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan ...@@ -73,12 +72,10 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
} }
def onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) = key match { def onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) = key match {
case Key.isNAT => if (ShadowsocksApplication.isRoot && activity != null) { case Key.isNAT => activity.handler.post(() => {
activity.handler.post(() => { activity.deattachService
activity.deattachService activity.attachService
activity.attachService })
})
}
case _ => case _ =>
} }
} }
...@@ -55,8 +55,6 @@ import org.apache.commons.net.util.SubnetUtils ...@@ -55,8 +55,6 @@ import org.apache.commons.net.util.SubnetUtils
import scala.collection.JavaConversions._ import scala.collection.JavaConversions._
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
class ShadowsocksVpnService extends VpnService with BaseService { class ShadowsocksVpnService extends VpnService with BaseService {
val TAG = "ShadowsocksVpnService" val TAG = "ShadowsocksVpnService"
...@@ -122,7 +120,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -122,7 +120,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
vpnThread = null vpnThread = null
} }
notification.destroy() if (notification != null) notification.destroy()
// channge the state // channge the state
changeState(State.STOPPING) changeState(State.STOPPING)
...@@ -213,7 +211,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -213,7 +211,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
changeState(State.CONNECTING) changeState(State.CONNECTING)
Future { ThrowableFuture {
if (config.proxy == "198.199.101.152") { if (config.proxy == "198.199.101.152") {
val holder = ShadowsocksApplication.containerHolder val holder = ShadowsocksApplication.containerHolder
try { try {
......
package com.github
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
/**
* @author Mygod
*/
package object shadowsocks {
def ThrowableFuture[T](f: => T) = Future(f) onFailure {
case e: Throwable => e.printStackTrace()
}
}
package com.github.shadowsocks.preferences
import android.content.Context
import android.content.res.TypedArray
import android.preference.SwitchPreference
import android.util.AttributeSet
import com.github.shadowsocks.{R, ShadowsocksApplication}
/**
* TODO: No animations?
* @author Mygod
*/
final class NatSwitchPreference(context: Context, attrs: AttributeSet) extends SwitchPreference(context, attrs) {
private var disabled = false
override def isEnabled = super.isEnabled && !disabled
override def setEnabled(b: Boolean) = super.setEnabled(b && !disabled)
if (!ShadowsocksApplication.isRoot) {
disabled = true
setEnabled(false)
setSummary(R.string.nat_summary_no_root)
}
override def onGetDefaultValue(a: TypedArray, index: Int) =
(!ShadowsocksApplication.isVpnEnabled).asInstanceOf[AnyRef]
}
...@@ -75,17 +75,11 @@ object Console { ...@@ -75,17 +75,11 @@ object Console {
shell.close() shell.close()
} }
def runRootCommand(command: String): String = runRootCommand(Array(command)) def runRootCommand(commands: String*): String = runRootCommand(commands.toArray)
def runRootCommand(command: String, context: String): String = runRootCommand(Array(command), context) def runRootCommand(commands: Array[String]): String = {
def runRootCommand(commands: Array[String]): String = runRootCommand(commands, "u:r:init_shell:s0") val shell = openRootShell("u:r:init_shell:s0")
def runRootCommand(commands: Array[String], context: String): String = {
if (!isRoot) {
return null
}
val shell = openRootShell(context)
val sb = new StringBuilder val sb = new StringBuilder
shell.addCommand(commands, 0, ((commandCode: Int, exitCode: Int, output: util.List[String]) => { shell.addCommand(commands, 0, ((_, exitCode, output) => {
if (exitCode < 0) { if (exitCode < 0) {
shell.close() shell.close()
} else { } else {
......
...@@ -140,12 +140,14 @@ object Utils { ...@@ -140,12 +140,14 @@ object Utils {
} }
// Blocked > 3 seconds // Blocked > 3 seconds
def toggleAirplaneMode(context: Context) { def toggleAirplaneMode(context: Context) = {
if (ShadowsocksApplication.isRoot) { if (Console.isRoot) {
Console.runRootCommand(Array("ndc resolver flushdefaultif", "ndc resolver flushif wlan0")) Console.runRootCommand("ndc resolver flushdefaultif", "ndc resolver flushif wlan0")
true
} else if (Build.VERSION.SDK_INT < 17) { } else if (Build.VERSION.SDK_INT < 17) {
toggleBelowApiLevel17(context) toggleBelowApiLevel17(context)
} true
} else false
} }
//noinspection ScalaDeprecation //noinspection ScalaDeprecation
...@@ -305,8 +307,7 @@ object Utils { ...@@ -305,8 +307,7 @@ object Utils {
var compatible: Boolean = false var compatible: Boolean = false
var version: Boolean = false var version: Boolean = false
val command = Array(iptables + " --version", iptables + " -L -t nat -n") val lines = Console.runRootCommand(iptables + " --version", iptables + " -L -t nat -n")
val lines = Console.runRootCommand(command)
if (lines == null) return if (lines == null) return
if (lines.contains("OUTPUT")) { if (lines.contains("OUTPUT")) {
...@@ -384,9 +385,7 @@ object Utils { ...@@ -384,9 +385,7 @@ object Utils {
hasRedirectSupport = 1 hasRedirectSupport = 1
val command = Utils.getIptables + " -t nat -A OUTPUT -p udp --dport 54 -j REDIRECT --to 8154" val command = Utils.getIptables + " -t nat -A OUTPUT -p udp --dport 54 -j REDIRECT --to 8154"
val lines = Console.runRootCommand(command) val lines = Console.runRootCommand(command, command.replace("-A", "-D"))
Console.runRootCommand(command.replace("-A", "-D"))
if (lines == null) return if (lines == null) return
if (lines.contains("No chain/target/match")) { if (lines.contains("No chain/target/match")) {
hasRedirectSupport = 0 hasRedirectSupport = 0
......
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