diff --git a/play-services-droidguard/core/src/main/AndroidManifest.xml b/play-services-droidguard/core/src/main/AndroidManifest.xml
index aa2a2ffe9f..11d36f59a5 100644
--- a/play-services-droidguard/core/src/main/AndroidManifest.xml
+++ b/play-services-droidguard/core/src/main/AndroidManifest.xml
@@ -7,6 +7,8 @@
xmlns:tools="http://schemas.android.com/tools">
+
(1), new ThreadPoolExecutor.DiscardPolicy());
HardwareAttestationBlockingProvider.ensureEnabled(DroidGuardPreferences.isHardwareAttestationBlocked(this));
SerialUnflaky.INSTANCE.fetch();
+ ServiceCallProxy.INSTANCE.maySetBlockDumpForService(this, "SurfaceFlinger");
+ ServiceCallProxy.INSTANCE.maySetBlockDumpForService(this, "thermalservice");
super.onCreate();
}
diff --git a/play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/ServiceCallProxy.kt b/play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/ServiceCallProxy.kt
new file mode 100644
index 0000000000..0e1e7db0f1
--- /dev/null
+++ b/play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/ServiceCallProxy.kt
@@ -0,0 +1,90 @@
+/*
+ * SPDX-FileCopyrightText: 2026 microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.droidguard.core
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.IBinder
+import android.util.Log
+import androidx.core.content.ContextCompat
+import java.lang.reflect.Field
+import java.lang.reflect.Method
+import java.lang.reflect.Proxy
+
+private const val TAG = "DroidGuard"
+
+/**
+ * Helper to block the call to dump() on services
+ *
+ * We may want to extend this later to allow for arbitrary service call interceptions
+ */
+@SuppressLint("PrivateApi")
+object ServiceCallProxy {
+ private var serviceManagerClass: Class<*>? = null
+ private var getServiceMethod: Method? = null
+ private var activeServices: MutableMap? = null
+ private val proxyEnabled: MutableMap = hashMapOf()
+ private val originalServices: MutableMap = hashMapOf()
+
+ init {
+ try {
+ serviceManagerClass = Class.forName("android.os.ServiceManager")
+ getServiceMethod =
+ serviceManagerClass!!.getDeclaredMethod("getService", String::class.java)
+ getServiceMethod!!.isAccessible = true
+ val cacheField: Field = serviceManagerClass!!.getDeclaredField("sCache")
+ cacheField.isAccessible = true
+ @Suppress("UNCHECKED_CAST")
+ activeServices = cacheField.get(null) as MutableMap?
+ } catch (e: Exception) {
+ Log.w(TAG, "Error configuring DumpBlockingProxy", e)
+ }
+ }
+
+ fun maySetBlockDumpForService(context: Context, systemServiceName: String) {
+ val permissionResult =
+ ContextCompat.checkSelfPermission(context, android.Manifest.permission.DUMP)
+ if (permissionResult == PackageManager.PERMISSION_DENIED) {
+ setBlockDumpForService(systemServiceName, true)
+ } else if (permissionResult == PackageManager.PERMISSION_GRANTED) {
+ setBlockDumpForService(systemServiceName, false)
+ }
+ }
+
+ fun setBlockDumpForService(systemServiceName: String, enabled: Boolean) {
+ if (proxyEnabled.containsKey(systemServiceName) && proxyEnabled[systemServiceName] == enabled) return
+ if (getServiceMethod == null || activeServices == null) return
+ Log.d(TAG, "Configuring blocker for dump() on service $systemServiceName")
+ if (enabled) {
+ val originalService = try {
+ getServiceMethod!!.invoke(null, systemServiceName) as IBinder
+ } catch (e: Exception) {
+ Log.w(TAG, e)
+ return
+ }
+ val newService = Proxy.newProxyInstance(
+ IBinder::class.java.getClassLoader(),
+ arrayOf>(IBinder::class.java),
+ { _, method, args ->
+ when (method.name) {
+ "dump" -> {
+ Log.d(TAG, "Blocking dump() call on $systemServiceName");
+ null
+ }
+
+ else -> method.invoke(originalService, args)
+ }
+ }) as IBinder
+ originalServices[systemServiceName] = originalService
+ activeServices!![systemServiceName] = newService
+ proxyEnabled[systemServiceName] = true
+ } else if (proxyEnabled[systemServiceName] == true) {
+ activeServices!![systemServiceName] = originalServices[systemServiceName]
+ proxyEnabled[systemServiceName] = false
+ }
+ }
+}
\ No newline at end of file