Skip to content
This repository has been archived by the owner on Apr 3, 2021. It is now read-only.

Commit

Permalink
add proxy log and logcat
Browse files Browse the repository at this point in the history
  • Loading branch information
eycorsican committed Jan 7, 2019
1 parent c29ebf8 commit 1c57eda
Show file tree
Hide file tree
Showing 23 changed files with 628 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -220,7 +220,7 @@ Github Releases: https://github.com/eycorsican/Kitsunebi4Android/releases

## Build

You must first build the `tun2socks.aar` library from [this repo](https://github.com/eycorsican/go-tun2socks-android) and copy it into `app/libs`, get `geoip.dat` and `geosite.dat` from the latest v2ray-core release and copy them into `app/src/main/res/raw`.
You must first build/download the `tun2socks.aar` library from [this repo](https://github.com/eycorsican/go-tun2socks-android/releases) and copy into `app/libs`, get `geoip.dat` and `geosite.dat` from [these](https://github.com/v2ray/geoip/releases) [two](https://github.com/v2ray/domain-list-community/releases) repos and copy them into `app/src/main/res/raw`, don't forget renaming them.

## 开发相关问题

Expand Down
25 changes: 16 additions & 9 deletions app/build.gradle
Expand Up @@ -4,15 +4,17 @@ apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

apply plugin: 'kotlin-kapt'

android {
compileSdkVersion 28
defaultConfig {
applicationId 'fun.kitsunebi.kitsunebi4android'
minSdkVersion 17
targetSdkVersion 28
versionCode 14
versionName "0.6.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
versionCode 16
versionName "0.7.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
Expand All @@ -27,14 +29,19 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.android.support:design:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'
implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha01'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3'
implementation 'com.google.android.material:material:1.1.0-alpha02'
implementation "androidx.paging:paging-runtime:2.1.0-rc01"
implementation 'com.beust:klaxon:3.0.1'
implementation(name: 'tun2socks', ext: 'aar')

implementation 'androidx.room:room-runtime:2.1.0-alpha03'
kapt 'androidx.room:room-compiler:2.1.0-alpha03'

implementation "androidx.lifecycle:lifecycle-extensions:2.1.0-alpha01"
kapt "androidx.lifecycle:lifecycle-compiler:2.1.0-alpha01"
}

repositories {
Expand Down
16 changes: 14 additions & 2 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -15,7 +15,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name="fun.kitsunebi.kitsunebi4android.ui.MainActivity"
android:name=".ui.MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
Expand All @@ -25,8 +25,20 @@
</intent-filter>
</activity>

<activity
android:name=".ui.ProxyLogActivity"
android:label="Proxy Logs"
android:parentActivityName=".ui.MainActivity">
</activity>

<activity
android:name=".ui.LogcatActivity"
android:label="Logcat"
android:parentActivityName=".ui.MainActivity">
</activity>

<service
android:name="fun.kitsunebi.kitsunebi4android.service.SimpleVpnService"
android:name=".service.SimpleVpnService"
android:permission="android.permission.BIND_VPN_SERVICE" >
<intent-filter>
<action android:name="android.net.VpnService" />
Expand Down
33 changes: 33 additions & 0 deletions app/src/main/java/fun/kitsunebi/kitsunebi4android/common/utils.kt
@@ -0,0 +1,33 @@
package `fun`.kitsunebi.kitsunebi4android.common

open class SingletonHolder<out T, in A>(creator: (A) -> T) {
private var creator: ((A) -> T)? = creator
@Volatile private var instance: T? = null

fun getInstance(arg: A): T {
val i = instance
if (i != null) {
return i
}

return synchronized(this) {
val i2 = instance
if (i2 != null) {
i2
} else {
val created = creator!!(arg)
instance = created
creator = null
created
}
}
}
}

public fun humanReadableByteCount(bytes: Long, si: Boolean): String {
val unit = if (si) 1000 else 1024
if (bytes < unit) return bytes.toString() + " B"
val exp = (Math.log(bytes.toDouble()) / Math.log(unit.toDouble())).toInt()
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
return String.format("%.1f %sB", bytes / Math.pow(unit.toDouble(), exp.toDouble()), pre)
}
@@ -1,6 +1,9 @@
package `fun`.kitsunebi.kitsunebi4android.service

import `fun`.kitsunebi.kitsunebi4android.R
import `fun`.kitsunebi.kitsunebi4android.storage.PROXY_LOG_DB_NAME
import `fun`.kitsunebi.kitsunebi4android.storage.ProxyLog
import `fun`.kitsunebi.kitsunebi4android.storage.ProxyLogDatabase
import android.annotation.TargetApi
import android.content.BroadcastReceiver
import android.content.Context
Expand All @@ -12,6 +15,7 @@ import android.os.ParcelFileDescriptor
import tun2socks.PacketFlow
import tun2socks.Tun2socks
import tun2socks.VpnService as Tun2socksVpnService
import tun2socks.DBService as Tun2socksDBService
import kotlin.concurrent.thread
import com.beust.klaxon.Klaxon
import java.io.FileInputStream
Expand Down Expand Up @@ -77,7 +81,6 @@ open class SimpleVpnService: VpnService() {
sendBroadcast(Intent("pong"))
}
}

}
}
}
Expand Down Expand Up @@ -107,6 +110,24 @@ open class SimpleVpnService: VpnService() {
}
}

class DBService(db: ProxyLogDatabase): Tun2socksDBService {
private val db = db
override fun insertProxyLog(p0: String?, p1: String?, p2: Long, p3: Long, p4: Int, p5: Int, p6: Int, p7: Int, p8: String?, p9: String?, p10: Int) {
db.proxyLogDao().insertAll(ProxyLog(0,
p0,
p1,
p2,
p3,
p4,
p5,
p6,
p7,
p8,
p9,
p10))
}
}

private fun handlePackets() {
while (!isStopped) {
val n = inputStream?.read(buffer.array())
Expand Down Expand Up @@ -151,7 +172,6 @@ open class SimpleVpnService: VpnService() {
return@thread
}


pfd = Builder().setSession("vv")
.setMtu(1500)
.addAddress("10.233.233.233", 30)
Expand Down Expand Up @@ -179,6 +199,7 @@ open class SimpleVpnService: VpnService() {

val flow = Flow(outputStream)
val service = Service(this)
val dbService = DBService(ProxyLogDatabase.getInstance(applicationContext))

val files = filesDir.list()
if (!files.contains("geoip.dat") || !files.contains("geosite.dat")) {
Expand All @@ -193,8 +214,11 @@ open class SimpleVpnService: VpnService() {
fos2.close()
}

ProxyLogDatabase.getInstance(applicationContext).proxyLogDao().getAllCount()
val dbPath = getDatabasePath(PROXY_LOG_DB_NAME).absolutePath

Tun2socks.setLocalDNS("223.5.5.5:53")
Tun2socks.startV2Ray(flow, service, configString.toByteArray(), filesDir.absolutePath)
Tun2socks.startV2Ray(flow, service, dbService, configString.toByteArray(), filesDir.absolutePath, dbPath)

sendBroadcast(Intent("vpn_started"))

Expand Down
@@ -0,0 +1,57 @@
package `fun`.kitsunebi.kitsunebi4android.storage

import androidx.room.*
import `fun`.kitsunebi.kitsunebi4android.common.SingletonHolder
import androidx.paging.DataSource
import android.content.Context

public const val PROXY_LOG_DB_NAME = "proxy_log.sqlite3"

@Entity(tableName = "proxy_log")
data class ProxyLog(
@PrimaryKey(autoGenerate = true) var id: Int,
@ColumnInfo(name = "target") var target: String?,
@ColumnInfo(name = "tag") var tag: String?,
@ColumnInfo(name = "start_time") var startTime: Long?,
@ColumnInfo(name = "end_time") var endTime: Long?,
@ColumnInfo(name = "upload_bytes") var uploadBytes: Int?,
@ColumnInfo(name = "download_bytes") var downloadBytes: Int?,
@ColumnInfo(name = "record_type") var recordType: Int?,
@ColumnInfo(name = "dns_query_type") var dnsQueryType: Int?,
@ColumnInfo(name = "dns_request") var dnsRequest: String?,
@ColumnInfo(name = "dns_response") var dnsResponse: String?,
@ColumnInfo(name = "dns_num_ips") var dnsNumIPs: Int?
)

@Dao
interface ProxyLogDao {
@Query("SELECT * FROM proxy_log")
fun getAll(): List<ProxyLog>

@Query("SELECT * FROM proxy_log ORDER BY end_time DESC")
fun getAllPaged(): DataSource.Factory<Int, ProxyLog>

@Insert
fun insertAll(proxyLogs: ProxyLog)

@Delete
fun delete(proxyLog: ProxyLog)

@Query("DELETE FROM proxy_log")
fun deleteAll()

@Query("SELECT COUNT(1) FROM proxy_log")
fun getAllCount(): Int
}

@Database(entities = arrayOf(ProxyLog::class), version = 4)
abstract class ProxyLogDatabase : RoomDatabase() {
abstract fun proxyLogDao(): ProxyLogDao
companion object : SingletonHolder<ProxyLogDatabase, Context>({
Room.databaseBuilder(it.applicationContext,
ProxyLogDatabase::class.java, PROXY_LOG_DB_NAME)
.fallbackToDestructiveMigration()
.enableMultiInstanceInvalidation()
.build()
})
}
@@ -0,0 +1,88 @@
package `fun`.kitsunebi.kitsunebi4android.ui

import `fun`.kitsunebi.kitsunebi4android.R
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import android.widget.TextView
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.util.*
import kotlin.concurrent.schedule
import kotlin.concurrent.scheduleAtFixedRate


class LogcatActivity : AppCompatActivity() {

private lateinit var logcatTextView: TextView
private lateinit var bgThread: Thread
private lateinit var logBuilder: StringBuilder
private lateinit var bgTimer: Timer

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_logcat)
logcatTextView = findViewById<TextView>(R.id.logcat_text)
logcatTextView.movementMethod = ScrollingMovementMethod()

bgThread = object : Thread() {
override fun run() {
try {
logBuilder = StringBuilder()
bgTimer = Timer()
val process = Runtime.getRuntime().exec("logcat")
val bufferedReader = BufferedReader(InputStreamReader(process.inputStream))
fun readAndDisplay() {
while (bufferedReader.ready()) {
val line = bufferedReader.readLine()
logBuilder.append(line + "\n")

}
runOnUiThread {
logcatTextView.text = logBuilder.toString()
}
}
bgTimer.schedule(1000) {
readAndDisplay()
}
bgTimer.scheduleAtFixedRate(0, 5000) {
readAndDisplay()
}
} catch (e: IOException) {
println(e)
}
}
}
bgThread.start()
}

override fun onDestroy() {
super.onDestroy()
bgTimer.cancel()
bgThread.interrupt()
}


override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_logcat, menu)
return true
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.copy_btn -> {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip: ClipData = ClipData.newPlainText("logcat text", logBuilder.toString())
clipboard.primaryClip = clip
return true
}
else -> super.onOptionsItemSelected(item)
}
}
}
Expand Up @@ -2,11 +2,12 @@ package `fun`.kitsunebi.kitsunebi4android.ui

import `fun`.kitsunebi.kitsunebi4android.R
import `fun`.kitsunebi.kitsunebi4android.service.SimpleVpnService
import `fun`.kitsunebi.kitsunebi4android.storage.*
import android.app.Activity
import android.app.AlertDialog
import android.content.Context
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import androidx.appcompat.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem

Expand Down Expand Up @@ -138,6 +139,16 @@ class MainActivity : AppCompatActivity() {
}
return true
}
R.id.log_btn -> {
val intent = Intent(this, ProxyLogActivity::class.java)
startActivity(intent)
return true
}
R.id.logcat_btn -> {
val intent = Intent(this, LogcatActivity::class.java)
startActivity(intent)
return true
}
R.id.help_btn -> {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/eycorsican/kitsunebi-android"))
startActivity(intent)
Expand Down

0 comments on commit 1c57eda

Please sign in to comment.