Move su logs out of magiskdb

This commit is contained in:
topjohnwu 2019-11-14 00:01:06 -05:00
parent a7f0510a3e
commit 576efbdc1b
11 changed files with 81 additions and 105 deletions

View File

@ -113,6 +113,7 @@ dependencies {
} }
def vRoom = '2.2.1' def vRoom = '2.2.1'
implementation "com.github.topjohnwu:room-runtime:${vRoom}" implementation "com.github.topjohnwu:room-runtime:${vRoom}"
implementation "androidx.room:room-rxjava2:${vRoom}"
kapt "androidx.room:room-compiler:${vRoom}" kapt "androidx.room:room-compiler:${vRoom}"
def vNav = '2.1.0' def vNav = '2.1.0'

View File

@ -11,6 +11,8 @@ import androidx.work.impl.WorkDatabase
import androidx.work.impl.WorkDatabase_Impl import androidx.work.impl.WorkDatabase_Impl
import com.topjohnwu.magisk.data.database.RepoDatabase import com.topjohnwu.magisk.data.database.RepoDatabase
import com.topjohnwu.magisk.data.database.RepoDatabase_Impl import com.topjohnwu.magisk.data.database.RepoDatabase_Impl
import com.topjohnwu.magisk.data.database.SuLogDatabase
import com.topjohnwu.magisk.data.database.SuLogDatabase_Impl
import com.topjohnwu.magisk.di.ActivityTracker import com.topjohnwu.magisk.di.ActivityTracker
import com.topjohnwu.magisk.di.koinModules import com.topjohnwu.magisk.di.koinModules
import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.get
@ -40,6 +42,7 @@ open class App() : Application() {
when (it) { when (it) {
WorkDatabase::class.java -> WorkDatabase_Impl() WorkDatabase::class.java -> WorkDatabase_Impl()
RepoDatabase::class.java -> RepoDatabase_Impl() RepoDatabase::class.java -> RepoDatabase_Impl()
SuLogDatabase::class.java -> SuLogDatabase_Impl()
else -> null else -> null
} }
} }

View File

@ -1,33 +0,0 @@
package com.topjohnwu.magisk.data.database
import com.topjohnwu.magisk.data.database.magiskdb.*
import com.topjohnwu.magisk.model.entity.MagiskLog
import com.topjohnwu.magisk.model.entity.toLog
import com.topjohnwu.magisk.model.entity.toMap
import java.util.concurrent.TimeUnit
class LogDao : BaseDao() {
override val table = Table.LOG
fun deleteOutdated(
suTimeout: Long = TimeUnit.DAYS.toMillis(14)
) = query<Delete> {
condition {
lessThan("time", suTimeout.toString())
}
}.ignoreElement()
fun deleteAll() = query<Delete>().ignoreElement()
fun fetchAll() = query<Select> {
orderBy("time", Order.DESC)
}.flattenAsFlowable { it }
.map { it.toLog() }
.toList()
fun put(log: MagiskLog) = query<Insert> {
values(log.toMap())
}.ignoreElement()
}

View File

@ -0,0 +1,36 @@
package com.topjohnwu.magisk.data.database
import androidx.room.*
import com.topjohnwu.magisk.model.entity.MagiskLog
import io.reactivex.Completable
import io.reactivex.Single
import java.util.*
@Database(version = 1, entities = [MagiskLog::class])
abstract class SuLogDatabase : RoomDatabase() {
abstract fun suLogDao(): SuLogDao
}
@Dao
abstract class SuLogDao(private val db: SuLogDatabase) {
private val twoWeeksAgo =
Calendar.getInstance().apply { add(Calendar.WEEK_OF_YEAR, -2) }.timeInMillis
fun deleteAll() = Completable.fromAction { db.clearAllTables() }
fun fetchAll() = deleteOutdated().andThen(fetch())
@Query("SELECT * FROM logs ORDER BY time DESC")
protected abstract fun fetch(): Single<MutableList<MagiskLog>>
@Insert
abstract fun insert(log: MagiskLog): Completable
@Query("DELETE FROM logs WHERE time < :timeout")
protected abstract fun deleteOutdated(
timeout: Long = twoWeeksAgo
): Completable
}

View File

@ -1,39 +1,36 @@
package com.topjohnwu.magisk.data.repository package com.topjohnwu.magisk.data.repository
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.data.database.LogDao import com.topjohnwu.magisk.data.database.SuLogDao
import com.topjohnwu.magisk.extensions.toSingle
import com.topjohnwu.magisk.model.entity.MagiskLog import com.topjohnwu.magisk.model.entity.MagiskLog
import com.topjohnwu.magisk.model.entity.WrappedMagiskLog import com.topjohnwu.magisk.model.entity.WrappedMagiskLog
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import io.reactivex.Completable
import io.reactivex.Single import io.reactivex.Single
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class LogRepository( class LogRepository(
private val logDao: LogDao private val logDao: SuLogDao
) { ) {
fun fetchLogs() = logDao.fetchAll() fun fetchLogs() = logDao.fetchAll().map { it.wrap() }
.map { it.sortByDescending { it.date.time }; it }
.map { it.wrap() }
fun fetchMagiskLogs() = Single.fromCallable { fun fetchMagiskLogs() = Single.fromCallable {
Shell.su("tail -n 5000 ${Const.MAGISK_LOG}").exec().out Shell.su("tail -n 5000 ${Const.MAGISK_LOG}").exec().out
}.filter { it.isNotEmpty() } }.flattenAsFlowable { it }.filter { it.isNotEmpty() }
fun clearLogs() = logDao.deleteAll() fun clearLogs() = logDao.deleteAll()
fun clearOutdated() = logDao.deleteOutdated()
fun clearMagiskLogs() = Shell.su("echo -n > " + Const.MAGISK_LOG) fun clearMagiskLogs() = Completable.fromAction {
.toSingle() Shell.su("echo -n > ${Const.MAGISK_LOG}").exec()
.map { it.exec() } }
fun put(log: MagiskLog) = logDao.put(log) fun insert(log: MagiskLog) = logDao.insert(log)
private fun List<MagiskLog>.wrap(): List<WrappedMagiskLog> { private fun List<MagiskLog>.wrap(): List<WrappedMagiskLog> {
val day = TimeUnit.DAYS.toMillis(1) val day = TimeUnit.DAYS.toMillis(1)
return groupBy { it.date.time / day } return groupBy { it.time / day }
.map { WrappedMagiskLog(it.key * day, it.value) } .map { WrappedMagiskLog(it.key * day, it.value) }
} }

View File

@ -8,11 +8,11 @@ import org.koin.dsl.module
val databaseModule = module { val databaseModule = module {
single { LogDao() }
single { PolicyDao(get()) } single { PolicyDao(get()) }
single { SettingsDao() } single { SettingsDao() }
single { StringDao() } single { StringDao() }
single { createRepoDatabase(get()).repoDao() } single { createRepoDatabase(get()).repoDao() }
single { createSuLogDatabase(get(Protected)).suLogDao() }
single { RepoUpdater(get(), get()) } single { RepoUpdater(get(), get()) }
} }
@ -20,3 +20,8 @@ fun createRepoDatabase(context: Context) =
Room.databaseBuilder(context, RepoDatabase::class.java, "repo.db") Room.databaseBuilder(context, RepoDatabase::class.java, "repo.db")
.fallbackToDestructiveMigration() .fallbackToDestructiveMigration()
.build() .build()
fun createSuLogDatabase(context: Context) =
Room.databaseBuilder(context, SuLogDatabase::class.java, "sulogs.db")
.fallbackToDestructiveMigration()
.build()

View File

@ -1,10 +1,14 @@
package com.topjohnwu.magisk.model.entity package com.topjohnwu.magisk.model.entity
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
import com.topjohnwu.magisk.extensions.now
import com.topjohnwu.magisk.extensions.timeFormatTime import com.topjohnwu.magisk.extensions.timeFormatTime
import com.topjohnwu.magisk.extensions.toTime import com.topjohnwu.magisk.extensions.toTime
import com.topjohnwu.magisk.model.entity.MagiskPolicy.Companion.ALLOW import com.topjohnwu.magisk.model.entity.MagiskPolicy.Companion.ALLOW
import java.util.*
@Entity(tableName = "logs")
data class MagiskLog( data class MagiskLog(
val fromUid: Int, val fromUid: Int,
val toUid: Int, val toUid: Int,
@ -13,9 +17,10 @@ data class MagiskLog(
val appName: String, val appName: String,
val command: String, val command: String,
val action: Boolean, val action: Boolean,
val date: Date val time: Long = -1
) { ) {
val timeString = date.time.toTime(timeFormatTime) @PrimaryKey(autoGenerate = true) var id: Int = 0
@Ignore val timeString = time.toTime(timeFormatTime)
} }
data class WrappedMagiskLog( data class WrappedMagiskLog(
@ -23,35 +28,8 @@ data class WrappedMagiskLog(
val items: List<MagiskLog> val items: List<MagiskLog>
) )
fun Map<String, String>.toLog(): MagiskLog {
return MagiskLog(
fromUid = get("from_uid")?.toIntOrNull() ?: -1,
toUid = get("to_uid")?.toIntOrNull() ?: -1,
fromPid = get("from_pid")?.toIntOrNull() ?: -1,
packageName = get("package_name").orEmpty(),
appName = get("app_name").orEmpty(),
command = get("command").orEmpty(),
action = get("action")?.toIntOrNull() != 0,
date = get("time")?.toLongOrNull()?.toDate() ?: Date()
)
}
fun Long.toDate() = Date(this)
fun MagiskLog.toMap() = mapOf(
"from_uid" to fromUid,
"to_uid" to toUid,
"from_pid" to fromPid,
"package_name" to packageName,
"app_name" to appName,
"command" to command,
"action" to action,
"time" to date.time
)
fun MagiskPolicy.toLog( fun MagiskPolicy.toLog(
toUid: Int, toUid: Int,
fromPid: Int, fromPid: Int,
command: String, command: String
date: Date ) = MagiskLog(uid, toUid, fromPid, packageName, appName, command, policy == ALLOW, now)
) = MagiskLog(uid, toUid, fromPid, packageName, appName, command, policy == ALLOW, date)

View File

@ -50,13 +50,7 @@ class LogItemEntryRvItem(val item: MagiskLog) : ComparableRvItem<LogItemEntryRvI
fun toggle() = isExpanded.toggle() fun toggle() = isExpanded.toggle()
override fun contentSameAs(other: LogItemEntryRvItem) = item.fromUid == other.item.fromUid && override fun contentSameAs(other: LogItemEntryRvItem) = item == other.item
item.toUid == other.item.toUid &&
item.fromPid == other.item.fromPid &&
item.packageName == other.item.packageName &&
item.command == other.item.command &&
item.action == other.item.action &&
item.date == other.item.date
override fun itemSameAs(other: LogItemEntryRvItem) = item.appName == other.item.appName override fun itemSameAs(other: LogItemEntryRvItem) = item.appName == other.item.appName
} }

View File

@ -104,7 +104,6 @@ class LogViewModel(
.add() .add()
private fun clearMagiskLogs(callback: () -> Unit) = logRepo.clearMagiskLogs() private fun clearMagiskLogs(callback: () -> Unit) = logRepo.clearMagiskLogs()
.ignoreElement()
.doOnComplete(callback) .doOnComplete(callback)
.subscribeK { SnackbarEvent(R.string.logs_cleared).publish() } .subscribeK { SnackbarEvent(R.string.logs_cleared).publish() }
.add() .add()
@ -115,7 +114,6 @@ class LogViewModel(
.toList() .toList()
private fun fetchMagiskLog() = logRepo.fetchMagiskLogs() private fun fetchMagiskLog() = logRepo.fetchMagiskLogs()
.flattenAsFlowable { it }
.map { ConsoleRvItem(it) } .map { ConsoleRvItem(it) }
.toList() .toList()

View File

@ -18,7 +18,6 @@ import com.topjohnwu.magisk.model.entity.toPolicy
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import timber.log.Timber import timber.log.Timber
import java.util.*
object SuHandler : ProviderCallHandler { object SuHandler : ProviderCallHandler {
@ -101,12 +100,11 @@ object SuHandler : ProviderCallHandler {
val log = policy.toLog( val log = policy.toLog(
toUid = toUid, toUid = toUid,
fromPid = pid, fromPid = pid,
command = command, command = command
date = Date()
) )
val logRepo = get<LogRepository>() val logRepo = get<LogRepository>()
logRepo.put(log).subscribeK(onError = { Timber.e(it) }) logRepo.insert(log).subscribeK(onError = { Timber.e(it) })
} }
private fun handleNotify(context: Context, data: Bundle) { private fun handleNotify(context: Context, data: Bundle) {

View File

@ -10,7 +10,7 @@
#include <daemon.h> #include <daemon.h>
#include <utils.h> #include <utils.h>
#define DB_VERSION 9 #define DB_VERSION 10
using namespace std; using namespace std;
@ -72,13 +72,6 @@ static char *open_and_init_db(sqlite3 *&db) {
"logging INT, notification INT, PRIMARY KEY(uid))", "logging INT, notification INT, PRIMARY KEY(uid))",
nullptr, nullptr, &err); nullptr, nullptr, &err);
err_ret(err); err_ret(err);
// Logs
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS logs "
"(from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, "
"to_uid INT, action INT, time INT, command TEXT)",
nullptr, nullptr, &err);
err_ret(err);
// Settings // Settings
sqlite3_exec(db, sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS settings " "CREATE TABLE IF NOT EXISTS settings "
@ -144,6 +137,12 @@ static char *open_and_init_db(sqlite3 *&db) {
ver = 9; ver = 9;
upgrade = true; upgrade = true;
} }
if (ver < 10) {
sqlite3_exec(db, "DROP TABLE logs", nullptr, nullptr, &err);
err_ret(err);
ver = 10;
upgrade = true;
}
if (upgrade) { if (upgrade) {
// Set version // Set version