Skip to content

Commit 5ae1c57

Browse files
committed
Support Android 17 beta3
1 parent efc1ade commit 5ae1c57

2 files changed

Lines changed: 39 additions & 17 deletions

File tree

daemon/src/main/kotlin/org/matrix/vector/daemon/system/SystemExtensions.kt

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ import android.content.IntentFilter
88
import android.content.pm.IPackageManager
99
import android.content.pm.PackageInfo
1010
import android.content.pm.PackageManager
11+
import android.content.pm.ParceledListSlice
1112
import android.content.pm.ResolveInfo
1213
import android.content.pm.ServiceInfo
1314
import android.os.Build
1415
import android.os.IUserManager
1516
import android.util.Log
17+
import java.lang.reflect.Method
1618
import org.matrix.vector.daemon.utils.getRealUsers
1719

1820
private const val TAG = "VectorSystem"
@@ -131,6 +133,37 @@ fun IPackageManager.clearApplicationProfileDataCompat(packageName: String) {
131133
runCatching { clearApplicationProfileData(packageName) }
132134
}
133135

136+
/** Cached method reference to avoid repeated reflection lookups in loops. */
137+
private val getInstalledPackagesMethod: Method? by lazy {
138+
val isLongFlags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
139+
android.content.pm.IPackageManager::class
140+
.java
141+
.declaredMethods
142+
.find {
143+
it.name == "getInstalledPackages" &&
144+
it.parameterTypes.size == 2 &&
145+
it.parameterTypes[0] ==
146+
(if (isLongFlags) Long::class.javaPrimitiveType else Int::class.javaPrimitiveType)
147+
}
148+
?.apply { isAccessible = true }
149+
}
150+
151+
/**
152+
* Reflectively calls getInstalledPackages and casts to ParceledListSlice. This works on Android 17+
153+
* because PackageInfoList extends ParceledListSlice.
154+
*/
155+
private fun IPackageManager.getInstalledPackagesReflect(
156+
flags: Any,
157+
userId: Int
158+
): List<PackageInfo> {
159+
val method = getInstalledPackagesMethod ?: return emptyList()
160+
return runCatching {
161+
val result = method.invoke(this, flags, userId)
162+
@Suppress("UNCHECKED_CAST") (result as? ParceledListSlice<PackageInfo>)?.list
163+
}
164+
.getOrNull() ?: emptyList()
165+
}
166+
134167
fun IPackageManager.getInstalledPackagesForAllUsers(
135168
flags: Int,
136169
filterNoProcess: Boolean
@@ -139,16 +172,12 @@ fun IPackageManager.getInstalledPackagesForAllUsers(
139172
val users = userManager?.getRealUsers() ?: emptyList()
140173

141174
for (user in users) {
142-
val infos =
143-
runCatching {
144-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
145-
getInstalledPackages(flags.toLong(), user.id)
146-
} else {
147-
getInstalledPackages(flags, user.id)
148-
}
149-
}
150-
.getOrNull()
151-
?.list ?: continue
175+
// We pass flags as Any so the reflective invoke handles Long or Int correctly
176+
val flagParam: Any =
177+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) flags.toLong() else flags
178+
179+
val infos = getInstalledPackagesReflect(flagParam, user.id)
180+
if (infos.isEmpty()) continue
152181

153182
result.addAll(
154183
infos.filter {

hiddenapi/stubs/src/main/java/android/content/pm/IPackageManager.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,6 @@ PackageInfo getPackageInfo(String packageName, long flags, int userId)
3838
String[] getPackagesForUid(int uid)
3939
throws RemoteException;
4040

41-
ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId)
42-
throws RemoteException;
43-
44-
@RequiresApi(33)
45-
ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId)
46-
throws RemoteException;
47-
4841
ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId)
4942
throws RemoteException;
5043

0 commit comments

Comments
 (0)