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> {
val until = if (remain <= 0) {
remain
} else {
MagiskDB.Literal("(strftime(\"%s\", \"now\") + $remain)")
}
return mutableMapOf(
"uid" to uid, "uid" to uid,
"policy" to policy, "policy" to policy,
"until" to until, "until" to until,
"logging" to logging, "logging" to logging,
"notification" to notification "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);
} }
} }