Commit ed9acb66 authored by Mygod's avatar Mygod

Migrate to Crashlytics

parent 96f5441e
...@@ -21,12 +21,16 @@ buildscript { ...@@ -21,12 +21,16 @@ buildscript {
repositories { repositories {
google() google()
jcenter() jcenter()
maven {
url 'https://maven.fabric.io/public'
}
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.0-beta03' classpath 'com.android.tools.build:gradle:3.2.0-beta03'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0' classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0'
classpath 'com.google.gms:google-services:4.0.1' classpath 'com.google.gms:google-services:4.0.1'
classpath 'io.fabric.tools:gradle:1.25.4'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
} }
} }
......
...@@ -3,6 +3,7 @@ import java.util.regex.Matcher ...@@ -3,6 +3,7 @@ import java.util.regex.Matcher
import java.util.regex.Pattern import java.util.regex.Pattern
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
...@@ -66,6 +67,7 @@ dependencies { ...@@ -66,6 +67,7 @@ dependencies {
implementation "com.android.support:design:$supportLibraryVersion" implementation "com.android.support:design:$supportLibraryVersion"
implementation "com.android.support:gridlayout-v7:$supportLibraryVersion" implementation "com.android.support:gridlayout-v7:$supportLibraryVersion"
implementation "com.android.support:support-v4:$supportLibraryVersion" implementation "com.android.support:support-v4:$supportLibraryVersion"
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.4'
implementation 'com.futuremind.recyclerfastscroll:fastscroll:0.2.5' implementation 'com.futuremind.recyclerfastscroll:fastscroll:0.2.5'
implementation "com.google.android.gms:play-services-ads:15.0.1" implementation "com.google.android.gms:play-services-ads:15.0.1"
implementation "com.google.android.gms:play-services-analytics:16.0.0" implementation "com.google.android.gms:play-services-analytics:16.0.0"
......
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
android:value="@integer/google_play_services_version"/> android:value="@integer/google_play_services_version"/>
<meta-data android:name="com.google.android.backup.api_key" <meta-data android:name="com.google.android.backup.api_key"
android:value="AEdPqrEAAAAI_zVxZthz2HDuz9toTvkYvL0L5GA-OjeUIfBeXg"/> android:value="AEdPqrEAAAAI_zVxZthz2HDuz9toTvkYvL0L5GA-OjeUIfBeXg"/>
<meta-data android:name="firebase_crashlytics_collection_enabled"
android:value="false"/>
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
......
...@@ -39,6 +39,7 @@ import android.support.annotation.RequiresApi ...@@ -39,6 +39,7 @@ import android.support.annotation.RequiresApi
import android.support.v7.app.AppCompatDelegate import android.support.v7.app.AppCompatDelegate
import android.util.Log import android.util.Log
import androidx.work.WorkManager import androidx.work.WorkManager
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.acl.Acl import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.database.Profile import com.github.shadowsocks.database.Profile
...@@ -49,11 +50,11 @@ import com.github.shadowsocks.preference.IconListPreference ...@@ -49,11 +50,11 @@ import com.github.shadowsocks.preference.IconListPreference
import com.github.shadowsocks.utils.* import com.github.shadowsocks.utils.*
import com.google.android.gms.analytics.GoogleAnalytics import com.google.android.gms.analytics.GoogleAnalytics
import com.google.android.gms.analytics.HitBuilders import com.google.android.gms.analytics.HitBuilders
import com.google.android.gms.analytics.StandardExceptionParser
import com.google.android.gms.analytics.Tracker import com.google.android.gms.analytics.Tracker
import com.google.firebase.FirebaseApp import com.google.firebase.FirebaseApp
import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.takisoft.fix.support.v7.preference.PreferenceFragmentCompat import com.takisoft.fix.support.v7.preference.PreferenceFragmentCompat
import io.fabric.sdk.android.Fabric
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
...@@ -67,7 +68,6 @@ class App : Application() { ...@@ -67,7 +68,6 @@ class App : Application() {
val deviceContext: Context by lazy { if (Build.VERSION.SDK_INT < 24) this else DeviceContext(this) } val deviceContext: Context by lazy { if (Build.VERSION.SDK_INT < 24) this else DeviceContext(this) }
val remoteConfig: FirebaseRemoteConfig by lazy { FirebaseRemoteConfig.getInstance() } val remoteConfig: FirebaseRemoteConfig by lazy { FirebaseRemoteConfig.getInstance() }
private val tracker: Tracker by lazy { GoogleAnalytics.getInstance(deviceContext).newTracker(R.xml.tracker) } private val tracker: Tracker by lazy { GoogleAnalytics.getInstance(deviceContext).newTracker(R.xml.tracker) }
private val exceptionParser by lazy { StandardExceptionParser(this, null) }
val info: PackageInfo by lazy { getPackageInfo(packageName) } val info: PackageInfo by lazy { getPackageInfo(packageName) }
val directBootSupported by lazy { val directBootSupported by lazy {
Build.VERSION.SDK_INT >= 24 && getSystemService(DevicePolicyManager::class.java) Build.VERSION.SDK_INT >= 24 && getSystemService(DevicePolicyManager::class.java)
...@@ -100,18 +100,11 @@ class App : Application() { ...@@ -100,18 +100,11 @@ class App : Application() {
.setAction(action) .setAction(action)
.setLabel(BuildConfig.VERSION_NAME) .setLabel(BuildConfig.VERSION_NAME)
.build()) .build())
fun track(t: Throwable) = track(Thread.currentThread(), t)
fun track(thread: Thread, t: Throwable) {
tracker.send(HitBuilders.ExceptionBuilder()
.setDescription("${exceptionParser.getDescription(thread.name, t)} - ${t.message}")
.setFatal(false)
.build())
t.printStackTrace()
}
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
app = this app = this
Fabric.with(this, Crashlytics()) // multiple processes needs manual set-up
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
PreferenceFragmentCompat.registerPreferenceFragment(IconListPreference::class.java, PreferenceFragmentCompat.registerPreferenceFragment(IconListPreference::class.java,
BottomSheetPreferenceDialogFragment::class.java) BottomSheetPreferenceDialogFragment::class.java)
...@@ -128,7 +121,10 @@ class App : Application() { ...@@ -128,7 +121,10 @@ class App : Application() {
FirebaseApp.initializeApp(deviceContext) FirebaseApp.initializeApp(deviceContext)
remoteConfig.setDefaults(R.xml.default_configs) remoteConfig.setDefaults(R.xml.default_configs)
remoteConfig.fetch().addOnCompleteListener { remoteConfig.fetch().addOnCompleteListener {
if (it.isSuccessful) remoteConfig.activateFetched() else Log.e(TAG, "Failed to fetch config") if (it.isSuccessful) remoteConfig.activateFetched() else {
Log.e(TAG, "Failed to fetch config")
Crashlytics.logException(it.exception)
}
} }
WorkManager.initialize(deviceContext, androidx.work.Configuration.Builder().build()) WorkManager.initialize(deviceContext, androidx.work.Configuration.Builder().build())
...@@ -144,8 +140,7 @@ class App : Application() { ...@@ -144,8 +140,7 @@ class App : Application() {
File(deviceContext.filesDir, file).outputStream().use { output -> input.copyTo(output) } File(deviceContext.filesDir, file).outputStream().use { output -> input.copyTo(output) }
} }
} catch (e: IOException) { } catch (e: IOException) {
Log.e(TAG, e.message) printLog(e)
app.track(e)
} }
DataStore.publicStore.putLong(Key.assetUpdateTime, info.lastUpdateTime) DataStore.publicStore.putLong(Key.assetUpdateTime, info.lastUpdateTime)
} }
......
...@@ -45,6 +45,7 @@ import android.text.format.Formatter ...@@ -45,6 +45,7 @@ import android.text.format.Formatter
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.acl.Acl import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.acl.CustomRulesFragment import com.github.shadowsocks.acl.CustomRulesFragment
...@@ -138,7 +139,6 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe ...@@ -138,7 +139,6 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
if (msg != null) { if (msg != null) {
Snackbar.make(findViewById(R.id.snackbar), Snackbar.make(findViewById(R.id.snackbar),
getString(R.string.vpn_error).format(Locale.ENGLISH, msg), Snackbar.LENGTH_LONG).show() getString(R.string.vpn_error).format(Locale.ENGLISH, msg), Snackbar.LENGTH_LONG).show()
Log.e(TAG, "Error to start VPN service: $msg")
} }
statusText.setText(R.string.not_connected) statusText.setText(R.string.not_connected)
} }
...@@ -211,7 +211,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe ...@@ -211,7 +211,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK) app.startService() else { if (resultCode == Activity.RESULT_OK) app.startService() else {
Snackbar.make(findViewById(R.id.snackbar), R.string.vpn_permission_denied, Snackbar.LENGTH_LONG).show() Snackbar.make(findViewById(R.id.snackbar), R.string.vpn_permission_denied, Snackbar.LENGTH_LONG).show()
Log.e(TAG, "Failed to start VpnService: $data") Crashlytics.log(Log.ERROR, TAG, "Failed to start VpnService from onActivityResult: $data")
} }
} }
......
...@@ -34,10 +34,12 @@ import android.util.Log ...@@ -34,10 +34,12 @@ import android.util.Log
import android.util.SparseArray import android.util.SparseArray
import android.view.MenuItem import android.view.MenuItem
import android.widget.Toast import android.widget.Toast
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.database.Profile import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.utils.openBitmap import com.github.shadowsocks.utils.openBitmap
import com.github.shadowsocks.utils.printLog
import com.github.shadowsocks.utils.resolveResourceId import com.github.shadowsocks.utils.resolveResourceId
import com.github.shadowsocks.utils.systemService import com.github.shadowsocks.utils.systemService
import com.google.android.gms.common.GoogleApiAvailability import com.google.android.gms.common.GoogleApiAvailability
...@@ -111,9 +113,7 @@ class ScannerActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListener, Ba ...@@ -111,9 +113,7 @@ class ScannerActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListener, Ba
} }
override fun onRetrievedMultiple(closetToClick: Barcode?, barcode: MutableList<BarcodeGraphic>?) = check(false) override fun onRetrievedMultiple(closetToClick: Barcode?, barcode: MutableList<BarcodeGraphic>?) = check(false)
override fun onBitmapScanned(sparseArray: SparseArray<Barcode>?) { } override fun onBitmapScanned(sparseArray: SparseArray<Barcode>?) { }
override fun onRetrievedFailed(reason: String?) { override fun onRetrievedFailed(reason: String?) = Crashlytics.log(Log.WARN, TAG, reason)
Log.w(TAG, reason)
}
override fun onPermissionRequestDenied() { override fun onPermissionRequestDenied() {
Toast.makeText(this, R.string.add_profile_scanner_permission_required, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.add_profile_scanner_permission_required, Toast.LENGTH_SHORT).show()
startImport() startImport()
...@@ -146,7 +146,7 @@ class ScannerActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListener, Ba ...@@ -146,7 +146,7 @@ class ScannerActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListener, Ba
success = true success = true
} }
} catch (e: Exception) { } catch (e: Exception) {
app.track(e) printLog(e)
} }
Toast.makeText(this, if (success) R.string.action_import_msg else R.string.action_import_err, Toast.makeText(this, if (success) R.string.action_import_msg else R.string.action_import_err,
Toast.LENGTH_SHORT).show() Toast.LENGTH_SHORT).show()
......
...@@ -26,8 +26,10 @@ import android.content.Intent ...@@ -26,8 +26,10 @@ import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.net.VpnService import android.net.VpnService
import android.os.Bundle import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.util.Log import android.util.Log
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.aidl.IShadowsocksService import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.bg.BaseService
...@@ -61,7 +63,10 @@ class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface ...@@ -61,7 +63,10 @@ class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == RESULT_OK) app.startService() else Log.e(TAG, "Failed to start VpnService") if (resultCode == RESULT_OK) app.startService() else {
Snackbar.make(findViewById(R.id.snackbar), R.string.vpn_permission_denied, Snackbar.LENGTH_LONG).show()
Crashlytics.log(Log.ERROR, TAG, "Failed to start VpnService from onActivityResult: $data")
}
finish() finish()
} }
......
...@@ -23,6 +23,7 @@ package com.github.shadowsocks.acl ...@@ -23,6 +23,7 @@ package com.github.shadowsocks.acl
import android.content.Context import android.content.Context
import android.support.v7.util.SortedList import android.support.v7.util.SortedList
import android.util.Log import android.util.Log
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.Subnet import com.github.shadowsocks.utils.Subnet
...@@ -164,7 +165,7 @@ class Acl { ...@@ -164,7 +165,7 @@ class Acl {
continue continue
} }
if (bypass != child.bypass) { if (bypass != child.bypass) {
Log.w(TAG, "Imported network ACL has a conflicting mode set. " + Crashlytics.log(Log.WARN, TAG, "Imported network ACL has a conflicting mode set. " +
"This will probably not work as intended. URL: $url") "This will probably not work as intended. URL: $url")
// rules for the different mode are discarded // rules for the different mode are discarded
child.hostnames.clear() child.hostnames.clear()
......
...@@ -45,10 +45,7 @@ import com.github.shadowsocks.MainActivity ...@@ -45,10 +45,7 @@ import com.github.shadowsocks.MainActivity
import com.github.shadowsocks.R import com.github.shadowsocks.R
import com.github.shadowsocks.ToolbarFragment import com.github.shadowsocks.ToolbarFragment
import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.utils.Subnet import com.github.shadowsocks.utils.*
import com.github.shadowsocks.utils.asIterable
import com.github.shadowsocks.utils.resolveResourceId
import com.github.shadowsocks.utils.systemService
import com.github.shadowsocks.widget.UndoSnackbarManager import com.github.shadowsocks.widget.UndoSnackbarManager
import java.net.IDN import java.net.IDN
import java.net.MalformedURLException import java.net.MalformedURLException
...@@ -443,7 +440,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener, ...@@ -443,7 +440,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
} catch (exc: Exception) { } catch (exc: Exception) {
Snackbar.make(requireActivity().findViewById(R.id.snackbar), R.string.action_import_err, Snackbar.make(requireActivity().findViewById(R.id.snackbar), R.string.action_import_err,
Snackbar.LENGTH_LONG).show() Snackbar.LENGTH_LONG).show()
app.track(exc) printLog(exc)
} }
true true
} }
......
...@@ -31,6 +31,7 @@ import android.os.RemoteCallbackList ...@@ -31,6 +31,7 @@ import android.os.RemoteCallbackList
import android.support.v4.os.UserManagerCompat import android.support.v4.os.UserManagerCompat
import android.util.Base64 import android.util.Base64
import android.util.Log import android.util.Log
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.R import com.github.shadowsocks.R
import com.github.shadowsocks.acl.Acl import com.github.shadowsocks.acl.Acl
...@@ -119,8 +120,7 @@ object BaseService { ...@@ -119,8 +120,7 @@ object BaseService {
if (bandwidthListeners.contains(item.asBinder())) if (bandwidthListeners.contains(item.asBinder()))
item.trafficUpdated(profile.id, txRate, rxRate, txTotal, rxTotal) item.trafficUpdated(profile.id, txRate, rxRate, txTotal, rxTotal)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() printLog(e)
app.track(e)
} }
callbacks.finishBroadcast() callbacks.finishBroadcast()
} }
...@@ -164,8 +164,7 @@ object BaseService { ...@@ -164,8 +164,7 @@ object BaseService {
val item = callbacks.getBroadcastItem(i) val item = callbacks.getBroadcastItem(i)
if (bandwidthListeners.contains(item.asBinder())) item.trafficPersisted(profile.id) if (bandwidthListeners.contains(item.asBinder())) item.trafficPersisted(profile.id)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() printLog(e)
app.track(e)
} }
} }
callbacks.finishBroadcast() callbacks.finishBroadcast()
...@@ -219,8 +218,7 @@ object BaseService { ...@@ -219,8 +218,7 @@ object BaseService {
for (i in 0 until n) try { for (i in 0 until n) try {
callbacks.getBroadcastItem(i).stateChanged(s, binder.profileName, msg) callbacks.getBroadcastItem(i).stateChanged(s, binder.profileName, msg)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() printLog(e)
app.track(e)
} }
callbacks.finishBroadcast() callbacks.finishBroadcast()
} }
...@@ -248,7 +246,7 @@ object BaseService { ...@@ -248,7 +246,7 @@ object BaseService {
stopRunner(false) stopRunner(false)
startRunner() startRunner()
} }
else -> Log.w(tag, "Illegal state when invoking use: $s") else -> Crashlytics.log(Log.WARN, tag, "Illegal state when invoking use: $s")
} }
} }
...@@ -416,7 +414,7 @@ object BaseService { ...@@ -416,7 +414,7 @@ object BaseService {
stopRunner(true, getString(R.string.reboot_required)) stopRunner(true, getString(R.string.reboot_required))
} catch (exc: Throwable) { } catch (exc: Throwable) {
stopRunner(true, "${getString(R.string.service_failed)}: ${exc.message}") stopRunner(true, "${getString(R.string.service_failed)}: ${exc.message}")
app.track(exc) printLog(exc)
} }
} }
return Service.START_NOT_STICKY return Service.START_NOT_STICKY
......
...@@ -22,6 +22,7 @@ package com.github.shadowsocks.bg ...@@ -22,6 +22,7 @@ package com.github.shadowsocks.bg
import android.text.TextUtils import android.text.TextUtils
import android.util.Log import android.util.Log
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.JniHelper import com.github.shadowsocks.JniHelper
import java.io.File import java.io.File
...@@ -34,7 +35,7 @@ object Executable { ...@@ -34,7 +35,7 @@ object Executable {
const val TUN2SOCKS = "libtun2socks.so" const val TUN2SOCKS = "libtun2socks.so"
const val OVERTURE = "liboverture.so" const val OVERTURE = "liboverture.so"
val EXECUTABLES = setOf(SS_LOCAL, SS_TUNNEL, REDSOCKS, TUN2SOCKS, OVERTURE) private val EXECUTABLES = setOf(SS_LOCAL, SS_TUNNEL, REDSOCKS, TUN2SOCKS, OVERTURE)
fun killAll() { fun killAll() {
for (process in File("/proc").listFiles { _, name -> TextUtils.isDigitsOnly(name) }) { for (process in File("/proc").listFiles { _, name -> TextUtils.isDigitsOnly(name) }) {
...@@ -45,7 +46,10 @@ object Executable { ...@@ -45,7 +46,10 @@ object Executable {
}.split(Character.MIN_VALUE, limit = 2).first()) }.split(Character.MIN_VALUE, limit = 2).first())
if (exe.parent == app.applicationInfo.nativeLibraryDir && EXECUTABLES.contains(exe.name)) { if (exe.parent == app.applicationInfo.nativeLibraryDir && EXECUTABLES.contains(exe.name)) {
val errno = JniHelper.sigkill(process.name.toInt()) val errno = JniHelper.sigkill(process.name.toInt())
if (errno != 0) Log.w("kill", "SIGKILL ${exe.absolutePath} (${process.name}) failed with $errno") if (errno != 0) {
Crashlytics.log(Log.WARN, "kill",
"SIGKILL ${exe.absolutePath} (${process.name}) failed with $errno")
}
} }
} }
} }
......
...@@ -23,8 +23,8 @@ package com.github.shadowsocks.bg ...@@ -23,8 +23,8 @@ package com.github.shadowsocks.bg
import android.os.Build import android.os.Build
import android.os.SystemClock import android.os.SystemClock
import android.util.Log import android.util.Log
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.BuildConfig
import com.github.shadowsocks.JniHelper import com.github.shadowsocks.JniHelper
import com.github.shadowsocks.utils.Commandline import com.github.shadowsocks.utils.Commandline
import com.github.shadowsocks.utils.thread import com.github.shadowsocks.utils.thread
...@@ -62,7 +62,7 @@ class GuardedProcessPool { ...@@ -62,7 +62,7 @@ class GuardedProcessPool {
try { try {
var callback: (() -> Unit)? = null var callback: (() -> Unit)? = null
while (guardThreads.get() === host) { while (guardThreads.get() === host) {
if (BuildConfig.DEBUG) Log.d(TAG, "start process: " + Commandline.toString(cmd)) Crashlytics.log(Log.DEBUG, TAG, "start process: " + Commandline.toString(cmd))
val startTime = SystemClock.elapsedRealtime() val startTime = SystemClock.elapsedRealtime()
process = ProcessBuilder(cmd) process = ProcessBuilder(cmd)
...@@ -79,11 +79,11 @@ class GuardedProcessPool { ...@@ -79,11 +79,11 @@ class GuardedProcessPool {
process.waitFor() process.waitFor()
if (SystemClock.elapsedRealtime() - startTime < 1000) { if (SystemClock.elapsedRealtime() - startTime < 1000) {
Log.w(TAG, "process exit too fast, stop guard: $cmdName") Crashlytics.log(Log.WARN, TAG, "process exit too fast, stop guard: $cmdName")
} }
} }
} catch (_: InterruptedException) { } catch (_: InterruptedException) {
if (BuildConfig.DEBUG) Log.d(TAG, "thread interrupt, destroy process: $cmdName") Crashlytics.log(Log.DEBUG, TAG, "thread interrupt, destroy process: $cmdName")
} catch (e: IOException) { } catch (e: IOException) {
pushException(e) pushException(e)
} finally { } finally {
......
...@@ -23,14 +23,14 @@ package com.github.shadowsocks.bg ...@@ -23,14 +23,14 @@ package com.github.shadowsocks.bg
import android.net.LocalServerSocket import android.net.LocalServerSocket
import android.net.LocalSocket import android.net.LocalSocket
import android.net.LocalSocketAddress import android.net.LocalSocketAddress
import android.util.Log
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.utils.printLog
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
abstract class LocalSocketListener(protected val tag: String) : Thread(tag) { abstract class LocalSocketListener(protected val tag: String) : Thread(tag) {
init { init {
setUncaughtExceptionHandler(app::track) setUncaughtExceptionHandler { _, t -> printLog(t) }
} }
protected abstract val socketFile: File protected abstract val socketFile: File
...@@ -48,15 +48,14 @@ abstract class LocalSocketListener(protected val tag: String) : Thread(tag) { ...@@ -48,15 +48,14 @@ abstract class LocalSocketListener(protected val tag: String) : Thread(tag) {
localSocket.bind(LocalSocketAddress(socketFile.absolutePath, LocalSocketAddress.Namespace.FILESYSTEM)) localSocket.bind(LocalSocketAddress(socketFile.absolutePath, LocalSocketAddress.Namespace.FILESYSTEM))
LocalServerSocket(localSocket.fileDescriptor) LocalServerSocket(localSocket.fileDescriptor)
} catch (e: IOException) { } catch (e: IOException) {
Log.e(tag, "unable to bind", e) printLog(e)
return return
} }
while (running) { while (running) {
try { try {
serverSocket.accept() serverSocket.accept()
} catch (e: IOException) { } catch (e: IOException) {
Log.e(tag, "Error when accept socket", e) printLog(e)
app.track(e)
null null
}?.use(this::accept) }?.use(this::accept)
} }
......
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
package com.github.shadowsocks.bg package com.github.shadowsocks.bg
import android.net.LocalSocket import android.net.LocalSocket
import android.util.Log
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.utils.printLog
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.nio.ByteBuffer import java.nio.ByteBuffer
...@@ -38,8 +38,7 @@ class TrafficMonitorThread : LocalSocketListener("TrafficMonitorThread") { ...@@ -38,8 +38,7 @@ class TrafficMonitorThread : LocalSocketListener("TrafficMonitorThread") {
val stat = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN) val stat = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN)
TrafficMonitor.update(stat.getLong(0), stat.getLong(8)) TrafficMonitor.update(stat.getLong(0), stat.getLong(8))
} catch (e: IOException) { } catch (e: IOException) {
Log.e(tag, "Error when recv traffic stat", e) printLog(e)
app.track(e)
} }
} }
} }
...@@ -28,7 +28,6 @@ import android.net.* ...@@ -28,7 +28,6 @@ import android.net.*
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import android.util.Log
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.JniHelper import com.github.shadowsocks.JniHelper
import com.github.shadowsocks.MainActivity import com.github.shadowsocks.MainActivity
...@@ -38,6 +37,7 @@ import com.github.shadowsocks.acl.Acl ...@@ -38,6 +37,7 @@ import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.Subnet import com.github.shadowsocks.utils.Subnet
import com.github.shadowsocks.utils.parseNumericAddress import com.github.shadowsocks.utils.parseNumericAddress
import com.github.shadowsocks.utils.printLog
import com.github.shadowsocks.utils.systemService import com.github.shadowsocks.utils.systemService
import java.io.File import java.io.File
import java.io.FileDescriptor import java.io.FileDescriptor
...@@ -74,32 +74,21 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -74,32 +74,21 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
override val socketFile: File = File(app.deviceContext.filesDir, "protect_path") override val socketFile: File = File(app.deviceContext.filesDir, "protect_path")
override fun accept(socket: LocalSocket) { override fun accept(socket: LocalSocket) {
var success = false
try { try {
socket.inputStream.read() socket.inputStream.read()
val fd = socket.ancillaryFileDescriptors!!.single()!! val fd = socket.ancillaryFileDescriptors!!.single()!!
val fdInt = getInt.invoke(fd) as Int val fdInt = getInt.invoke(fd) as Int
try { socket.outputStream.write(if (try {
val network = underlyingNetwork val network = underlyingNetwork
success = if (network != null && Build.VERSION.SDK_INT >= 23) { if (network != null && Build.VERSION.SDK_INT >= 23) {
network.bindSocket(fd) network.bindSocket(fd)
true true
} else protect(fdInt) } else protect(fdInt)
} catch (e: Exception) { } finally {
Log.e(tag, "Error when protect socket", e) JniHelper.close(fdInt) // Trick to close file decriptor
app.track(e) }) 0 else 1)
} finally {
JniHelper.close(fdInt) // Trick to close file decriptor
}
} catch (e: Exception) {
Log.e(tag, "Error when receiving ancillary fd", e)
app.track(e)
}
try {
socket.outputStream.write(if (success) 0 else 1)
} catch (e: IOException) { } catch (e: IOException) {
Log.e(tag, "Error when returning result in protect", e) printLog(e)
app.track(e)
} }
} }
} }
...@@ -207,7 +196,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -207,7 +196,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
if (profile.bypass) builder.addDisallowedApplication(it) if (profile.bypass) builder.addDisallowedApplication(it)
else builder.addAllowedApplication(it) else builder.addAllowedApplication(it)
} catch (ex: PackageManager.NameNotFoundException) { } catch (ex: PackageManager.NameNotFoundException) {
Log.e(tag, "Invalid package name", ex) printLog(ex)
} }
} }
if (!profile.bypass) builder.addAllowedApplication(me) if (!profile.bypass) builder.addAllowedApplication(me)
......
...@@ -21,11 +21,11 @@ ...@@ -21,11 +21,11 @@
package com.github.shadowsocks.database package com.github.shadowsocks.database
import android.database.sqlite.SQLiteCantOpenDatabaseException import android.database.sqlite.SQLiteCantOpenDatabaseException
import android.util.Log
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.ProfilesFragment import com.github.shadowsocks.ProfilesFragment
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.DirectBoot import com.github.shadowsocks.utils.DirectBoot
import com.github.shadowsocks.utils.printLog
import java.io.IOException import java.io.IOException
import java.sql.SQLException import java.sql.SQLException
...@@ -67,8 +67,7 @@ object ProfileManager { ...@@ -67,8 +67,7 @@ object ProfileManager {
PrivateDatabase.profileDao[id] PrivateDatabase.profileDao[id]
} catch (ex: SQLException) { } catch (ex: SQLException) {
if (ex.cause is SQLiteCantOpenDatabaseException) throw IOException(ex) if (ex.cause is SQLiteCantOpenDatabaseException) throw IOException(ex)
Log.e(TAG, "getProfile", ex) printLog(ex)
app.track(ex)
null null
} }
...@@ -84,8 +83,7 @@ object ProfileManager { ...@@ -84,8 +83,7 @@ object ProfileManager {
PrivateDatabase.profileDao.isNotEmpty() PrivateDatabase.profileDao.isNotEmpty()
} catch (ex: SQLException) { } catch (ex: SQLException) {
if (ex.cause is SQLiteCantOpenDatabaseException) throw IOException(ex) if (ex.cause is SQLiteCantOpenDatabaseException) throw IOException(ex)
Log.e(TAG, "isNotEmpty", ex) printLog(ex)
app.track(ex)
false false
} }
...@@ -94,8 +92,7 @@ object ProfileManager { ...@@ -94,8 +92,7 @@ object ProfileManager {
PrivateDatabase.profileDao.list() PrivateDatabase.profileDao.list()
} catch (ex: SQLException) { } catch (ex: SQLException) {
if (ex.cause is SQLiteCantOpenDatabaseException) throw IOException(ex) if (ex.cause is SQLiteCantOpenDatabaseException) throw IOException(ex)
Log.e(TAG, "getAllProfiles", ex) printLog(ex)
app.track(ex)
null null
} }
} }
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
package com.github.shadowsocks.plugin package com.github.shadowsocks.plugin
import android.util.Log import android.util.Log
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.utils.Commandline import com.github.shadowsocks.utils.Commandline
import java.util.* import java.util.*
...@@ -43,7 +44,7 @@ class PluginConfiguration(val pluginsOptions: Map<String, PluginOptions>, val se ...@@ -43,7 +44,7 @@ class PluginConfiguration(val pluginsOptions: Map<String, PluginOptions>, val se
} }
} }
} catch (exc: Exception) { } catch (exc: Exception) {
Log.w("PluginConfiguration", exc.message) Crashlytics.log(Log.WARN, "PluginConfiguration", exc.message)
} }
opt opt
} else PluginOptions(line) } else PluginOptions(line)
......
...@@ -30,6 +30,7 @@ import android.net.Uri ...@@ -30,6 +30,7 @@ import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Base64 import android.util.Base64
import android.util.Log import android.util.Log
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.utils.Commandline import com.github.shadowsocks.utils.Commandline
import com.github.shadowsocks.utils.signaturesCompat import com.github.shadowsocks.utils.signaturesCompat
...@@ -143,7 +144,8 @@ object PluginManager { ...@@ -143,7 +144,8 @@ object PluginManager {
initNativeFast(cr, options, uri) initNativeFast(cr, options, uri)
} catch (t: Throwable) { } catch (t: Throwable) {
t.printStackTrace() t.printStackTrace()
Log.w("PluginManager", "Initializing native plugin fast mode failed. Falling back to slow mode.") Crashlytics.log(Log.WARN, "PluginManager",
"Initializing native plugin fast mode failed. Falling back to slow mode.")
initNativeSlow(cr, options, uri) initNativeSlow(cr, options, uri)
} }
} }
......
...@@ -14,6 +14,7 @@ import android.support.annotation.AttrRes ...@@ -14,6 +14,7 @@ import android.support.annotation.AttrRes
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.support.v7.util.SortedList import android.support.v7.util.SortedList
import android.util.TypedValue import android.util.TypedValue
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.JniHelper import com.github.shadowsocks.JniHelper
import java.net.InetAddress import java.net.InetAddress
...@@ -40,7 +41,7 @@ fun broadcastReceiver(callback: (Context, Intent) -> Unit): BroadcastReceiver = ...@@ -40,7 +41,7 @@ fun broadcastReceiver(callback: (Context, Intent) -> Unit): BroadcastReceiver =
fun thread(name: String? = null, start: Boolean = true, isDaemon: Boolean = false, fun thread(name: String? = null, start: Boolean = true, isDaemon: Boolean = false,
contextClassLoader: ClassLoader? = null, priority: Int = -1, block: () -> Unit): Thread { contextClassLoader: ClassLoader? = null, priority: Int = -1, block: () -> Unit): Thread {
val thread = kotlin.concurrent.thread(false, isDaemon, contextClassLoader, name, priority, block) val thread = kotlin.concurrent.thread(false, isDaemon, contextClassLoader, name, priority, block)
thread.setUncaughtExceptionHandler(app::track) thread.setUncaughtExceptionHandler { _, t -> printLog(t) }
if (start) thread.start() if (start) thread.start()
return thread return thread
} }
...@@ -75,3 +76,9 @@ private class SortedListIterator<out T>(private val list: SortedList<T>) : Itera ...@@ -75,3 +76,9 @@ private class SortedListIterator<out T>(private val list: SortedList<T>) : Itera
override fun next(): T = if (hasNext()) list[count++] else throw NoSuchElementException() override fun next(): T = if (hasNext()) list[count++] else throw NoSuchElementException()
} }
fun <T> SortedList<T>.asIterable(): Iterable<T> = SortedListIterable(this) fun <T> SortedList<T>.asIterable(): Iterable<T> = SortedListIterable(this)
fun printLog(t: Throwable) {
Crashlytics.logException(t)
t.printStackTrace()
}
fun track(thread: Thread, t: Throwable) = printLog(t)
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