diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index 25cde98c..149d7797 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -78,6 +78,7 @@ object Typefaces { } catch { case e: Exception => Log.e(TAG, "Could not get typeface '" + assetPath + "' because " + e.getMessage) + app.track(e) return null } } @@ -185,8 +186,8 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext { snackbar.show } - if (!app.settings.getBoolean(app.getVersionName, false)) { - app.editor.putBoolean(app.getVersionName, true).apply() + if (!app.settings.getBoolean(BuildConfig.VERSION_NAME, false)) { + app.editor.putBoolean(BuildConfig.VERSION_NAME, true).apply() recovery() @@ -246,6 +247,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext { } catch { case e: IOException => Log.e(TAG, e.getMessage) + app.track(e) } if (files != null) { for (file <- files) { @@ -267,6 +269,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext { } catch { case ex: Exception => Log.e(TAG, ex.getMessage) + app.track(ex) } } } diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala index 71699eb4..aa46429d 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala @@ -43,12 +43,11 @@ import java.util import java.util.concurrent.TimeUnit import android.app.Application -import android.content.pm.PackageManager import android.preference.PreferenceManager import android.support.v7.app.AppCompatDelegate import com.github.shadowsocks.database.{DBHelper, ProfileManager} import com.github.shadowsocks.utils.{Key, Utils} -import com.google.android.gms.analytics.{GoogleAnalytics, HitBuilders} +import com.google.android.gms.analytics.{GoogleAnalytics, HitBuilders, StandardExceptionParser} import com.google.android.gms.common.api.ResultCallback import com.google.android.gms.tagmanager.{ContainerHolder, TagManager} import com.j256.ormlite.logger.LocalLog @@ -70,17 +69,14 @@ class ShadowsocksApplication extends Application { def isNatEnabled = settings.getBoolean(Key.isNAT, false) def isVpnEnabled = !isNatEnabled - def getVersionName = try { - getPackageManager.getPackageInfo(getPackageName, 0).versionName - } catch { - case _: PackageManager.NameNotFoundException => "Package name not found" - case _: Throwable => null - } - // send event def track(category: String, action: String) = tracker.send(new HitBuilders.EventBuilder() .setAction(action) - .setLabel(getVersionName) + .setLabel(BuildConfig.VERSION_NAME) + .build()) + def track(t: Throwable) = tracker.send(new HitBuilders.ExceptionBuilder() + .setDescription(new StandardExceptionParser(this, null).getDescription(Thread.currentThread.getName, t)) + .setFatal(false) .build()) def profileId = settings.getInt(Key.id, -1) diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala index 8aec2664..bcadcbb4 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala @@ -194,7 +194,7 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan }) new AlertDialog.Builder(activity) - .setTitle(getString(R.string.about_title).formatLocal(Locale.ENGLISH, app.getVersionName)) + .setTitle(getString(R.string.about_title).formatLocal(Locale.ENGLISH, BuildConfig.VERSION_NAME)) .setNegativeButton(getString(android.R.string.ok), null) .setView(web) .create() diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index bb136335..a95dc06c 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -48,9 +48,9 @@ import android.content.pm.PackageManager.NameNotFoundException import android.net.VpnService import android.os._ import android.util.Log -import com.github.shadowsocks.utils._ import com.github.shadowsocks.ShadowsocksApplication.app import com.github.shadowsocks.database.Profile +import com.github.shadowsocks.utils._ import scala.collection.mutable.ArrayBuffer @@ -368,7 +368,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { } } catch { case ex: NameNotFoundException => - Log.e(TAG, "Invalid package name", ex); + Log.e(TAG, "Invalid package name", ex) } } } @@ -390,17 +390,11 @@ class ShadowsocksVpnService extends VpnService with BaseService { conn = builder.establish() if (conn == null) changeState(State.STOPPED, getString(R.string.reboot_required)) } catch { - case ex: IllegalStateException => - changeState(State.STOPPED, ex.getMessage) - conn = null case ex: Exception => ex.printStackTrace() - conn = null - } - - if (conn == null) { - stopRunner(true) - return -1 + app.track(ex) + stopRunner(true, ex.getMessage) + return -1 } val fd = conn.getFd diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnThread.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnThread.scala index d1361327..b941daf9 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnThread.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnThread.scala @@ -44,6 +44,7 @@ import java.util.concurrent.Executors import android.net.{LocalServerSocket, LocalSocket, LocalSocketAddress} import android.util.Log +import com.github.shadowsocks.ShadowsocksApplication.app object ShadowsocksVpnThread { val getInt = classOf[FileDescriptor].getDeclaredMethod("getInt$") @@ -56,7 +57,7 @@ class ShadowsocksVpnThread(vpnService: ShadowsocksVpnService) extends Thread { lazy val PATH = vpnService.getApplicationInfo.dataDir + "/protect_path" @volatile var isRunning: Boolean = true - @volatile var serverSocket: LocalServerSocket = null + @volatile var serverSocket: LocalServerSocket = _ def closeServerSocket() { if (serverSocket != null) { @@ -76,11 +77,7 @@ class ShadowsocksVpnThread(vpnService: ShadowsocksVpnService) extends Thread { override def run() { - try { - new File(PATH).delete() - } catch { - case _: Exception => // ignore - } + new File(PATH).delete() try { val localSocket = new LocalSocket @@ -89,6 +86,7 @@ class ShadowsocksVpnThread(vpnService: ShadowsocksVpnService) extends Thread { } catch { case e: IOException => Log.e(TAG, "unable to bind", e) + app.track(e) return } @@ -127,6 +125,7 @@ class ShadowsocksVpnThread(vpnService: ShadowsocksVpnService) extends Thread { } catch { case e: Exception => Log.e(TAG, "Error when protect socket", e) + app.track(e) } // close socket @@ -140,6 +139,7 @@ class ShadowsocksVpnThread(vpnService: ShadowsocksVpnService) extends Thread { } catch { case e: IOException => Log.e(TAG, "Error when accept socket", e) + app.track(e) return } } diff --git a/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala b/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala index 76a59d57..6ddded9c 100644 --- a/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala +++ b/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala @@ -76,6 +76,7 @@ class ProfileManager(dbHelper: DBHelper) { } catch { case ex: Exception => Log.e(TAG, "addProfile", ex) + app.track(ex) p } } @@ -87,6 +88,7 @@ class ProfileManager(dbHelper: DBHelper) { } catch { case ex: Exception => Log.e(TAG, "updateProfile", ex) + app.track(ex) false } } @@ -100,6 +102,7 @@ class ProfileManager(dbHelper: DBHelper) { } catch { case ex: Exception => Log.e(TAG, "getProfile", ex) + app.track(ex) None } } @@ -111,6 +114,7 @@ class ProfileManager(dbHelper: DBHelper) { } catch { case ex: Exception => Log.e(TAG, "delProfile", ex) + app.track(ex) false } } @@ -122,6 +126,7 @@ class ProfileManager(dbHelper: DBHelper) { } catch { case ex: Exception => Log.e(TAG, "getAllProfiles", ex) + app.track(ex) None } } @@ -133,6 +138,7 @@ class ProfileManager(dbHelper: DBHelper) { } catch { case ex: Exception => Log.e(TAG, "getAllProfiles", ex) + app.track(ex) None } } diff --git a/src/main/scala/com/github/shadowsocks/utils/TrafficMonitorThread.scala b/src/main/scala/com/github/shadowsocks/utils/TrafficMonitorThread.scala index d17eddb1..8d7f3668 100644 --- a/src/main/scala/com/github/shadowsocks/utils/TrafficMonitorThread.scala +++ b/src/main/scala/com/github/shadowsocks/utils/TrafficMonitorThread.scala @@ -46,13 +46,14 @@ import java.util.concurrent.Executors import android.content.Context import android.net.{LocalServerSocket, LocalSocket, LocalSocketAddress} import android.util.Log +import com.github.shadowsocks.ShadowsocksApplication.app class TrafficMonitorThread(context: Context) extends Thread { val TAG = "TrafficMonitorThread" lazy val PATH = context.getApplicationInfo.dataDir + "/stat_path" - @volatile var serverSocket: LocalServerSocket = null + @volatile var serverSocket: LocalServerSocket = _ @volatile var isRunning: Boolean = true def closeServerSocket() { @@ -73,11 +74,7 @@ class TrafficMonitorThread(context: Context) extends Thread { override def run() { - try { - new File(PATH).delete() - } catch { - case _: Exception => // ignore - } + new File(PATH).delete() try { val localSocket = new LocalSocket @@ -113,6 +110,7 @@ class TrafficMonitorThread(context: Context) extends Thread { } catch { case e: Exception => Log.e(TAG, "Error when recv traffic stat", e) + app.track(e) } // close socket @@ -126,6 +124,7 @@ class TrafficMonitorThread(context: Context) extends Thread { } catch { case e: IOException => Log.e(TAG, "Error when accept socket", e) + app.track(e) return } } diff --git a/src/main/scala/com/github/shadowsocks/utils/Utils.scala b/src/main/scala/com/github/shadowsocks/utils/Utils.scala index 374140b6..691401ad 100644 --- a/src/main/scala/com/github/shadowsocks/utils/Utils.scala +++ b/src/main/scala/com/github/shadowsocks/utils/Utils.scala @@ -57,6 +57,7 @@ import com.github.shadowsocks.{BuildConfig, ShadowsocksRunnerService} import eu.chainfire.libsuperuser.Shell import org.xbill.DNS._ +import scala.collection.JavaConversions._ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future import scala.util.{Failure, Try} @@ -200,29 +201,22 @@ object Utils { */ def isIPv6Support: Boolean = { try { - val interfaces = NetworkInterface.getNetworkInterfaces - while (interfaces.hasMoreElements) { - val intf = interfaces.nextElement() - val addrs = intf.getInetAddresses - while (addrs.hasMoreElements) { - val addr = addrs.nextElement() - if (!addr.isLoopbackAddress && !addr.isLinkLocalAddress) { - if (addr.isInstanceOf[Inet6Address]) { - if (BuildConfig.DEBUG) Log.d(TAG, "IPv6 address detected") - return true - } + for (intf <- enumerationAsScalaIterator(NetworkInterface.getNetworkInterfaces)) + for (addr <- enumerationAsScalaIterator(intf.getInetAddresses)) + if (addr.isInstanceOf[Inet6Address] && !addr.isLoopbackAddress && !addr.isLinkLocalAddress) { + if (BuildConfig.DEBUG) Log.d(TAG, "IPv6 address detected") + return true } - } - } } catch { case ex: Exception => Log.e(TAG, "Failed to get interfaces' addresses.", ex) + app.track(ex) } false } def startSsService(context: Context) { - val isInstalled: Boolean = app.settings.getBoolean(app.getVersionName, false) + val isInstalled: Boolean = app.settings.getBoolean(BuildConfig.VERSION_NAME, false) if (!isInstalled) return val intent = new Intent(context, classOf[ShadowsocksRunnerService]) @@ -235,7 +229,9 @@ object Utils { } private val handleFailure: Try[_] => Unit = { - case Failure(e) => e.printStackTrace() + case Failure(e) => + e.printStackTrace() + app.track(e) case _ => }