Use SQLite's internal time function

This commit is contained in:
topjohnwu 2025-01-05 04:32:47 -08:00 committed by John Wu
parent b782e7dcb7
commit 0d31d356ef
10 changed files with 62 additions and 48 deletions

View File

@ -83,7 +83,7 @@ object Config : PreferenceConfig, DBConfig {
const val SU_AUTO_ALLOW = 2 const val SU_AUTO_ALLOW = 2
// su timeout // su timeout
val TIMEOUT_LIST = intArrayOf(0, -1, 10, 20, 30, 60) val TIMEOUT_LIST = longArrayOf(0, -1, 10, 20, 30, 60)
} }
private val defaultChannel = private val defaultChannel =

View File

@ -7,9 +7,13 @@ import kotlinx.coroutines.withContext
open class MagiskDB { open class MagiskDB {
suspend fun <R> exec( class Literal(
val str: String
)
suspend inline fun <R> exec(
query: String, query: String,
mapper: suspend (Map<String, String>) -> R crossinline mapper: (Map<String, String>) -> R
): List<R> { ): List<R> {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
val out = Shell.cmd("magisk --sqlite '$query'").await().out val out = Shell.cmd("magisk --sqlite '$query'").await().out
@ -18,13 +22,15 @@ open class MagiskDB {
.map { it.split("=", limit = 2) } .map { it.split("=", limit = 2) }
.filter { it.size == 2 } .filter { it.size == 2 }
.associate { it[0] to it[1] } .associate { it[0] to it[1] }
.let { mapper(it) } .let(mapper)
} }
} }
} }
suspend inline fun exec(query: String) { suspend fun exec(query: String) {
exec(query) {} withContext(Dispatchers.IO) {
Shell.cmd("magisk --sqlite '$query'").await()
}
} }
fun Map<String, Any>.toQuery(): String { fun Map<String, Any>.toQuery(): String {
@ -33,6 +39,7 @@ open class MagiskDB {
when (it) { when (it) {
is Boolean -> if (it) "1" else "0" is Boolean -> if (it) "1" else "0"
is Number -> it.toString() is Number -> it.toString()
is Literal -> it.str
else -> "\"$it\"" else -> "\"$it\""
} }
} }

View File

@ -3,24 +3,24 @@ package com.topjohnwu.magisk.core.data.magiskdb
import com.topjohnwu.magisk.core.AppContext import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.model.su.SuPolicy import com.topjohnwu.magisk.core.model.su.SuPolicy
import java.util.concurrent.TimeUnit
private const val SELECT_QUERY = "SELECT (until - strftime(\"%s\", \"now\")) AS remain, *"
class PolicyDao : MagiskDB() { class PolicyDao : MagiskDB() {
suspend fun deleteOutdated() { suspend fun deleteOutdated() {
val nowSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())
val query = "DELETE FROM ${Table.POLICY} WHERE " + val query = "DELETE FROM ${Table.POLICY} WHERE " +
"(until > 0 AND until < $nowSeconds) OR until < 0" "(until > 0 AND until < strftime(\"%s\", \"now\")) OR until < 0"
exec(query) exec(query)
} }
suspend fun delete(uid: Int) { suspend fun delete(uid: Int) {
val query = "DELETE FROM ${Table.POLICY} WHERE uid == $uid" val query = "DELETE FROM ${Table.POLICY} WHERE uid=$uid"
exec(query) exec(query)
} }
suspend fun fetch(uid: Int): SuPolicy? { suspend fun fetch(uid: Int): SuPolicy? {
val query = "SELECT * FROM ${Table.POLICY} WHERE uid == $uid LIMIT 1" val query = "$SELECT_QUERY FROM ${Table.POLICY} WHERE uid=$uid LIMIT 1"
return exec(query, ::toPolicy).firstOrNull() return exec(query, ::toPolicy).firstOrNull()
} }
@ -35,7 +35,7 @@ class PolicyDao : MagiskDB() {
} }
suspend fun fetchAll(): List<SuPolicy> { suspend fun fetchAll(): List<SuPolicy> {
val query = "SELECT * FROM ${Table.POLICY} WHERE uid/100000 == ${Const.USER_ID}" val query = "$SELECT_QUERY FROM ${Table.POLICY} WHERE uid/100000=${Const.USER_ID}"
return exec(query, ::toPolicy).filterNotNull() return exec(query, ::toPolicy).filterNotNull()
} }
@ -43,8 +43,15 @@ class PolicyDao : MagiskDB() {
val uid = map["uid"]?.toInt() ?: return null val uid = map["uid"]?.toInt() ?: return null
val policy = SuPolicy(uid) val policy = SuPolicy(uid)
map["until"]?.toLong()?.let { until ->
if (until <= 0) {
policy.remain = until
} else {
map["remain"]?.toLong()?.let { policy.remain = it }
}
}
map["policy"]?.toInt()?.let { policy.policy = it } map["policy"]?.toInt()?.let { policy.policy = it }
map["until"]?.toLong()?.let { policy.until = it }
map["logging"]?.toInt()?.let { policy.logging = it != 0 } map["logging"]?.toInt()?.let { policy.logging = it != 0 }
map["notification"]?.toInt()?.let { policy.notification = it != 0 } map["notification"]?.toInt()?.let { policy.notification = it != 0 }
return policy return policy

View File

@ -3,7 +3,7 @@ package com.topjohnwu.magisk.core.data.magiskdb
class SettingsDao : MagiskDB() { class SettingsDao : MagiskDB() {
suspend fun delete(key: String) { suspend fun delete(key: String) {
val query = "DELETE FROM ${Table.SETTINGS} WHERE key == \"$key\"" val query = "DELETE FROM ${Table.SETTINGS} WHERE key=\"$key\""
exec(query) exec(query)
} }
@ -14,7 +14,7 @@ class SettingsDao : MagiskDB() {
} }
suspend fun fetch(key: String, default: Int = -1): Int { suspend fun fetch(key: String, default: Int = -1): Int {
val query = "SELECT value FROM ${Table.SETTINGS} WHERE key == \"$key\" LIMIT 1" val query = "SELECT value FROM ${Table.SETTINGS} WHERE key=\"$key\" LIMIT 1"
return exec(query) { it["value"]?.toInt() }.firstOrNull() ?: default return exec(query) { it["value"]?.toInt() }.firstOrNull() ?: default
} }
} }

View File

@ -3,7 +3,7 @@ package com.topjohnwu.magisk.core.data.magiskdb
class StringDao : MagiskDB() { class StringDao : MagiskDB() {
suspend fun delete(key: String) { suspend fun delete(key: String) {
val query = "DELETE FROM ${Table.STRINGS} WHERE key == \"$key\"" val query = "DELETE FROM ${Table.STRINGS} WHERE key=\"$key\""
exec(query) exec(query)
} }
@ -14,7 +14,7 @@ class StringDao : MagiskDB() {
} }
suspend fun fetch(key: String, default: String = ""): String { suspend fun fetch(key: String, default: String = ""): String {
val query = "SELECT value FROM ${Table.STRINGS} WHERE key == \"$key\" LIMIT 1" val query = "SELECT value FROM ${Table.STRINGS} WHERE key=\"$key\" LIMIT 1"
return exec(query) { it["value"] }.firstOrNull() ?: default return exec(query) { it["value"] }.firstOrNull() ?: default
} }
} }

View File

@ -1,9 +1,11 @@
package com.topjohnwu.magisk.core.model.su package com.topjohnwu.magisk.core.model.su
import com.topjohnwu.magisk.core.data.magiskdb.MagiskDB
class SuPolicy( class SuPolicy(
val uid: Int, val uid: Int,
var policy: Int = INTERACTIVE, var policy: Int = INTERACTIVE,
var until: Long = -1L, var remain: Long = -1L,
var logging: Boolean = true, var logging: Boolean = true,
var notification: Boolean = true, var notification: Boolean = true,
) { ) {
@ -13,11 +15,18 @@ class SuPolicy(
const val ALLOW = 2 const val ALLOW = 2
} }
fun toMap(): MutableMap<String, Any> = mutableMapOf( fun toMap(): MutableMap<String, Any> {
"uid" to uid, val until = if (remain <= 0) {
"policy" to policy, remain
"until" to until, } else {
"logging" to logging, MagiskDB.Literal("(strftime(\"%s\", \"now\") + $remain)")
"notification" to notification }
) return mutableMapOf(
"uid" to uid,
"policy" to policy,
"until" to until,
"logging" to logging,
"notification" to notification
)
}
} }

View File

@ -81,15 +81,13 @@ class SuRequestHandler(
return true return true
} }
suspend fun respond(action: Int, time: Int) { suspend fun respond(action: Int, time: Long) {
val until = if (time > 0)
TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) +
TimeUnit.MINUTES.toSeconds(time.toLong())
else
time.toLong()
policy.policy = action policy.policy = action
policy.until = until if (time >= 0) {
policy.remain = TimeUnit.MINUTES.toSeconds(time)
} else {
policy.remain = time
}
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
try { try {
@ -100,7 +98,7 @@ class SuRequestHandler(
} catch (e: IOException) { } catch (e: IOException) {
Timber.e(e) Timber.e(e)
} }
if (until >= 0) { if (time >= 0) {
policyDB.update(policy) policyDB.update(policy)
} }
} }

View File

@ -45,7 +45,7 @@ class MagiskAppTest : BaseTest {
uid = 2000, uid = 2000,
logging = false, logging = false,
notification = false, notification = false,
until = 0L remain = 0L
) )
runBlocking { runBlocking {
ServiceLocator.policyDB.update(policy) ServiceLocator.policyDB.update(policy)

View File

@ -2,8 +2,7 @@ use crate::daemon::MagiskD;
use crate::db::DbArg::Integer; use crate::db::DbArg::Integer;
use crate::db::{SqlTable, SqliteResult, SqliteReturn}; use crate::db::{SqlTable, SqliteResult, SqliteReturn};
use crate::ffi::{DbValues, RootSettings, SuPolicy}; use crate::ffi::{DbValues, RootSettings, SuPolicy};
use base::{libc, ResultExt}; use base::ResultExt;
use std::ptr;
impl Default for SuPolicy { impl Default for SuPolicy {
fn default() -> Self { fn default() -> Self {
@ -40,11 +39,8 @@ impl MagiskD {
fn get_root_settings(&self, uid: i32, settings: &mut RootSettings) -> SqliteResult { fn get_root_settings(&self, uid: i32, settings: &mut RootSettings) -> SqliteResult {
self.db_exec_with_rows( self.db_exec_with_rows(
"SELECT policy, logging, notification FROM policies \ "SELECT policy, logging, notification FROM policies \
WHERE uid=? AND (until=0 OR until>?)", WHERE uid=? AND (until=0 OR until>strftime('%s', 'now'))",
&[ &[Integer(uid as i64)],
Integer(uid as i64),
Integer(unsafe { libc::time(ptr::null_mut()).into() }),
],
settings, settings,
) )
.sql_result() .sql_result()

View File

@ -111,9 +111,8 @@ bool uid_granted_root(int uid) {
} }
bool granted = false; bool granted = false;
db_exec("SELECT policy FROM policies WHERE uid=? AND (until=0 OR until>?)", db_exec("SELECT policy FROM policies WHERE uid=? AND (until=0 OR until>strftime('%s', 'now'))",
{ uid, time(nullptr) }, { uid }, [&](auto, const DbValues &v) { granted = v.get_int(0) == +SuPolicy::Allow; });
[&](auto, const DbValues &values) { granted = values.get_int(0) == +SuPolicy::Allow; });
return granted; return granted;
} }
@ -141,9 +140,7 @@ void prune_su_access() {
} }
} }
for (int uid : rm_uids) { for (int uid : rm_uids) {
char query[256]; db_exec("DELETE FROM policies WHERE uid=?", { uid });
ssprintf(query, sizeof(query), "DELETE FROM policies WHERE uid == %d", uid);
db_exec(query);
} }
} }