Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.matrix.vector.daemon.data

import android.os.Process

/** Pure process matching rules shared by the daemon policy and local unit tests. */
object InlineHookProcessPolicy {
fun matchesSystemUiVirtualPackage(
configuredPackages: Set<String>,
processName: String,
uid: Int
): Boolean =
SYSTEM_UI_VIRTUAL_PACKAGE in configuredPackages &&
uid == Process.SYSTEM_UID &&
processName == SYSTEM_UI_PROCESS

fun matchesPackage(
expectedUid: Int,
actualUid: Int,
processName: String,
applicationProcessName: String?,
componentProcesses: Set<String>
): Boolean =
expectedUid == actualUid &&
(processName == applicationProcessName || processName in componentProcesses)

fun mayInvalidate(processName: String, uid: Int): Boolean =
uid != Process.SYSTEM_UID || processName != "system"
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package org.matrix.vector.daemon.data
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import org.apache.commons.lang3.SerializationUtilsX
import org.matrix.vector.daemon.system.*

private const val TAG = "VectorPreferenceStore"
private const val INVALIDATE_ART_INLINE_HOOKS_KEY_PREFIX = "invalidate_art_inline_hooks:"
const val SYSTEM_UI_VIRTUAL_PACKAGE = "system"
const val SYSTEM_UI_PROCESS = "system:ui"

object PreferenceStore {

Expand Down Expand Up @@ -100,4 +104,56 @@ object PreferenceStore {
fun isScopeRequestBlocked(pkg: String): Boolean =
(getModulePrefs("lspd", 0, "config")["scope_request_blocked"] as? Set<*>)?.contains(pkg) ==
true

fun getInvalidateArtInlineHookPackages(): Set<String> {
return getModulePrefs("lspd", 0, "config")
.asSequence()
.filter { (key, value) ->
key.startsWith(INVALIDATE_ART_INLINE_HOOKS_KEY_PREFIX) && value == true
}
.map { (key, _) -> key.removePrefix(INVALIDATE_ART_INLINE_HOOKS_KEY_PREFIX) }
.filter { it.isNotBlank() }
.toSet()
}

/** Updates one package without replacing another Manager client's choices. */
fun setInvalidateArtInlineHooks(packageName: String, enabled: Boolean): Boolean {
val normalized = packageName.trim()
if (normalized.isEmpty()) return false
updateModulePref(
"lspd",
0,
"config",
INVALIDATE_ART_INLINE_HOOKS_KEY_PREFIX + normalized,
if (enabled) true else null)
return true
}

/**
* Resolves the configured package list against the actual process topology for this user.
* This deliberately avoids assuming that every Android process name starts with its package name.
*/
fun shouldInvalidateArtInlineHooks(processName: String, uid: Int): Boolean {
val configured = getInvalidateArtInlineHookPackages()
if (configured.isEmpty()) return false

if (InlineHookProcessPolicy.matchesSystemUiVirtualPackage(configured, processName, uid)) {
return true
}

val userId = uid / PER_USER_RANGE
return configured.any { packageName ->
if (packageName == SYSTEM_UI_VIRTUAL_PACKAGE) return@any false
val info =
packageManager?.getPackageInfoWithComponents(packageName, MATCH_ALL_FLAGS, userId)
?: return@any false
val applicationInfo = info.applicationInfo ?: return@any false
InlineHookProcessPolicy.matchesPackage(
expectedUid = applicationInfo.uid,
actualUid = uid,
processName = processName,
applicationProcessName = applicationInfo.processName,
componentProcesses = info.fetchProcesses())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import org.matrix.vector.ipc.IProcessChannel
import org.matrix.vector.ipc.IFrameworkService
import org.matrix.vector.daemon.data.ConfigCache
import org.matrix.vector.daemon.data.FileSystem
import org.matrix.vector.daemon.data.InlineHookProcessPolicy
import org.matrix.vector.daemon.data.PreferenceStore
import org.matrix.vector.daemon.system.FIRST_APPLICATION_UID
import org.matrix.vector.daemon.system.PER_USER_RANGE
import org.matrix.vector.daemon.utils.InstallerVerifier
Expand All @@ -29,6 +31,8 @@ const val DEX_TRANSACTION_CODE =
('_'.code shl 24) or ('D'.code shl 16) or ('E'.code shl 8) or 'X'.code
const val OBFUSCATION_MAP_TRANSACTION_CODE =
('_'.code shl 24) or ('O'.code shl 16) or ('B'.code shl 8) or 'F'.code
const val INVALIDATE_ART_INLINE_HOOKS_TRANSACTION_CODE =
('_'.code shl 24) or ('I'.code shl 16) or ('N'.code shl 8) or 'L'.code

/**
* What an injected process asks the framework for — this project's `IFrameworkService`.
Expand Down Expand Up @@ -241,6 +245,15 @@ object FrameworkService : IFrameworkService.Stub() {
}
return true
}
INVALIDATE_ART_INLINE_HOOKS_TRANSACTION_CODE -> {
val info = ensureRegistered()
val invalidate =
InlineHookProcessPolicy.mayInvalidate(info.processName, info.key.uid) &&
PreferenceStore.shouldInvalidateArtInlineHooks(info.processName, info.key.uid)
reply?.writeNoException()
reply?.writeInt(if (invalidate) 1 else 0)
return true
}
}
return super.onTransact(code, data, reply, flags)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,12 @@ object ManagerService : IManagerService.Stub() {
if (isVerboseLogEnabled()) LogcatMonitor.startVerbose() else LogcatMonitor.stopVerbose()
}

override fun getInvalidateArtInlineHookPackages(): MutableList<String> =
PreferenceStore.getInvalidateArtInlineHookPackages().sorted().toMutableList()

override fun setInvalidateArtInlineHooks(packageName: String, enabled: Boolean): Boolean =
PreferenceStore.setInvalidateArtInlineHooks(packageName, enabled)

override fun getLogParts(verbose: Boolean): List<String> = FileSystem.listLogParts(verbose)

override fun getLogPart(verbose: Boolean, name: String): ParcelFileDescriptor? =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ class FakeManagerService(
real?.setVerboseLogEnabled(enabled)
}

override fun getInvalidateArtInlineHookPackages(): MutableList<String> =
real?.invalidateArtInlineHookPackages.orEmpty().sorted().toMutableList()

override fun setInvalidateArtInlineHooks(packageName: String, enabled: Boolean): Boolean =
real?.setInvalidateArtInlineHooks(packageName, enabled) ?: false

override fun getLiveLogPart(verbose: Boolean): ParcelFileDescriptor? =
real?.getLiveLogPart(verbose)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,25 @@ class DaemonClient(private val serviceState: StateFlow<IManagerService?>) {
suspend fun setVerboseLogEnabled(enabled: Boolean): Result<Unit> = runIpc { it.setVerboseLogEnabled(enabled)
}

/**
* Every package opted into ART inline-hook invalidation, sorted.
*
* Empty against a daemon too old to answer the call, in which case the manager shows none.
*/
suspend fun getInvalidateArtInlineHookPackages(): Result<List<String>> = runIpc {
it.invalidateArtInlineHookPackages.orEmpty()
}

/**
* Sets whether a package invalidates Vector's native ART inline hooks after injection.
*
* [Result] carries the daemon's own answer: it stores the choice and reports whether the write
* landed, so a blank package name or a refused write reaches the caller rather than reading as a
* silent success.
*/
suspend fun setInvalidateArtInlineHooks(packageName: String, enabled: Boolean): Result<Boolean> =
runIpc { it.setInvalidateArtInlineHooks(packageName, enabled) }

/**
* The rotated parts the daemon still holds for one of the two logs, oldest first.
*
Expand Down
Loading