Commit a9a6e1c1 authored by Mygod's avatar Mygod Committed by Max Lv

Track caught exceptions (#810)

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