Skip to content

Commit d653e69

Browse files
committed
Fix package filtering
1 parent ced370e commit d653e69

3 files changed

Lines changed: 104 additions & 46 deletions

File tree

daemon/src/main/kotlin/org/matrix/vector/daemon/data/ConfigCache.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ object ConfigCache {
405405

406406
fun getInstalledModules(): List<ApplicationInfo> {
407407
val allPackages =
408-
packageManager?.getInstalledPackagesForAllUsers(MATCH_ALL_FLAGS, false) ?: emptyList()
408+
packageManager?.getInstalledPackagesFromAllUsers(MATCH_ALL_FLAGS, false) ?: emptyList()
409409
return allPackages
410410
.mapNotNull { it.applicationInfo }
411411
.filter { info -> getModuleApkPath(info) != null }

daemon/src/main/kotlin/org/matrix/vector/daemon/ipc/ManagerService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ object ManagerService : ILSPManagerService.Stub() {
221221
filterNoProcess: Boolean
222222
): ParcelableListSlice<PackageInfo> {
223223
return ParcelableListSlice(
224-
packageManager?.getInstalledPackagesForAllUsers(flags, filterNoProcess) ?: emptyList())
224+
packageManager?.getInstalledPackagesFromAllUsers(flags, filterNoProcess) ?: emptyList())
225225
}
226226

227227
override fun enabledModules() = ConfigCache.state.modules.keys.toTypedArray()

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

Lines changed: 102 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import android.content.pm.ServiceInfo
1414
import android.os.Build
1515
import android.os.IUserManager
1616
import android.util.Log
17+
import java.io.File
1718
import java.lang.reflect.Method
19+
import java.util.stream.Collectors
1820
import org.matrix.vector.daemon.utils.getRealUsers
1921

2022
private const val TAG = "VectorSystem"
@@ -27,27 +29,53 @@ const val MATCH_ALL_FLAGS =
2729
PackageManager.MATCH_UNINSTALLED_PACKAGES or
2830
MATCH_ANY_USER
2931

32+
/**
33+
* Internal helper that throws exceptions instead of swallowing them. This is crucial for detecting
34+
* TransactionTooLargeException (Binder limits).
35+
*/
36+
@Throws(Exception::class)
37+
private fun IPackageManager.getPackageInfoCompatThrows(
38+
packageName: String,
39+
flags: Int,
40+
userId: Int
41+
): PackageInfo? {
42+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
43+
getPackageInfo(packageName, flags.toLong(), userId)
44+
} else {
45+
getPackageInfo(packageName, flags, userId)
46+
}
47+
}
48+
3049
/** Safely fetches PackageInfo, handling API level differences. */
3150
fun IPackageManager.getPackageInfoCompat(
3251
packageName: String,
3352
flags: Int,
3453
userId: Int
3554
): PackageInfo? {
3655
return try {
37-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
38-
getPackageInfo(packageName, flags.toLong(), userId)
39-
} else {
40-
getPackageInfo(packageName, flags, userId)
41-
}
56+
getPackageInfoCompatThrows(packageName, flags, userId)
4257
} catch (e: Exception) {
4358
null
4459
}
4560
}
4661

4762
/**
48-
* Fetches PackageInfo alongside its components (Activities, Services, Receivers, Providers).
49-
* Includes a fallback mechanism to prevent TransactionTooLargeException on massive apps.
63+
* Checks if the package is truly available for the given user. Apps can be "installed" but
64+
* disabled/hidden by profile owners.
5065
*/
66+
fun IPackageManager.isPackageAvailable(
67+
packageName: String,
68+
userId: Int,
69+
ignoreHidden: Boolean
70+
): Boolean {
71+
return runCatching {
72+
isPackageAvailable(packageName, userId) ||
73+
(ignoreHidden && getApplicationHiddenSettingAsUser(packageName, userId))
74+
}
75+
.getOrDefault(false)
76+
}
77+
78+
/** Fetches PackageInfo alongside its components (Activities, Services, Receivers, Providers). */
5179
fun IPackageManager.getPackageInfoWithComponents(
5280
packageName: String,
5381
flags: Int,
@@ -60,33 +88,55 @@ fun IPackageManager.getPackageInfoWithComponents(
6088
PackageManager.GET_RECEIVERS or
6189
PackageManager.GET_PROVIDERS
6290

63-
// Fast path: Try fetching everything at once
64-
getPackageInfoCompat(packageName, fullFlags, userId)?.let {
65-
return it
66-
}
91+
var pkgInfo: PackageInfo? = null
6792

68-
// Fallback path: Fetch sequentially to avoid Binder Transaction limits
69-
val baseInfo = getPackageInfoCompat(packageName, flags, userId) ?: return null
93+
try {
94+
// If the binder buffer overflows, it will throw an exception here.
95+
pkgInfo = getPackageInfoCompatThrows(packageName, fullFlags, userId)
96+
} catch (e: Exception) {
97+
// Fallback path: Fetch sequentially if the initial query threw an Exception
98+
pkgInfo =
99+
try {
100+
getPackageInfoCompatThrows(packageName, flags, userId)
101+
} catch (ignored: Exception) {
102+
null
103+
}
70104

71-
runCatching {
72-
baseInfo.activities =
73-
getPackageInfoCompat(packageName, flags or PackageManager.GET_ACTIVITIES, userId)
74-
?.activities
75-
}
76-
runCatching {
77-
baseInfo.services =
78-
getPackageInfoCompat(packageName, flags or PackageManager.GET_SERVICES, userId)?.services
79-
}
80-
runCatching {
81-
baseInfo.receivers =
82-
getPackageInfoCompat(packageName, flags or PackageManager.GET_RECEIVERS, userId)?.receivers
105+
if (pkgInfo != null) {
106+
runCatching {
107+
pkgInfo.activities =
108+
getPackageInfoCompatThrows(packageName, flags or PackageManager.GET_ACTIVITIES, userId)
109+
?.activities
110+
}
111+
runCatching {
112+
pkgInfo.services =
113+
getPackageInfoCompatThrows(packageName, flags or PackageManager.GET_SERVICES, userId)
114+
?.services
115+
}
116+
runCatching {
117+
pkgInfo.receivers =
118+
getPackageInfoCompatThrows(packageName, flags or PackageManager.GET_RECEIVERS, userId)
119+
?.receivers
120+
}
121+
runCatching {
122+
pkgInfo.providers =
123+
getPackageInfoCompatThrows(packageName, flags or PackageManager.GET_PROVIDERS, userId)
124+
?.providers
125+
}
126+
}
83127
}
84-
runCatching {
85-
baseInfo.providers =
86-
getPackageInfoCompat(packageName, flags or PackageManager.GET_PROVIDERS, userId)?.providers
128+
129+
if (pkgInfo?.applicationInfo == null) return null
130+
if (pkgInfo.packageName != "android") {
131+
val sourceDir = pkgInfo.applicationInfo?.sourceDir
132+
if (sourceDir == null ||
133+
!File(sourceDir).exists() ||
134+
!isPackageAvailable(packageName, userId, true)) {
135+
return null
136+
}
87137
}
88138

89-
return baseInfo
139+
return pkgInfo
90140
}
91141

92142
/** Extracts all unique process names associated with a package's components. */
@@ -148,10 +198,7 @@ private val getInstalledPackagesMethod: Method? by lazy {
148198
?.apply { isAccessible = true }
149199
}
150200

151-
/**
152-
* Reflectively calls getInstalledPackages and casts to ParceledListSlice. This works on Android 17+
153-
* because PackageInfoList extends ParceledListSlice.
154-
*/
201+
/** Reflectively calls getInstalledPackages and casts to ParceledListSlice. */
155202
private fun IPackageManager.getInstalledPackagesReflect(
156203
flags: Any,
157204
userId: Int
@@ -164,11 +211,12 @@ private fun IPackageManager.getInstalledPackagesReflect(
164211
.getOrNull() ?: emptyList()
165212
}
166213

167-
fun IPackageManager.getInstalledPackagesForAllUsers(
214+
fun IPackageManager.getInstalledPackagesFromAllUsers(
168215
flags: Int,
169216
filterNoProcess: Boolean
170217
): List<PackageInfo> {
171218
val result = mutableListOf<PackageInfo>()
219+
// Assuming userManager is available in this scope as in original code
172220
val users = userManager?.getRealUsers() ?: emptyList()
173221

174222
for (user in users) {
@@ -179,20 +227,30 @@ fun IPackageManager.getInstalledPackagesForAllUsers(
179227
val infos = getInstalledPackagesReflect(flagParam, user.id)
180228
if (infos.isEmpty()) continue
181229

182-
result.addAll(
183-
infos.filter {
184-
it.applicationInfo != null && it.applicationInfo!!.uid / PER_USER_RANGE == user.id
185-
})
230+
val validUserApps =
231+
infos
232+
.parallelStream()
233+
.filter {
234+
it.applicationInfo != null && (it.applicationInfo!!.uid / PER_USER_RANGE) == user.id
235+
}
236+
.filter { isPackageAvailable(it.packageName, user.id, true) }
237+
.collect(Collectors.toList())
238+
239+
result.addAll(validUserApps)
186240
}
187241

188242
if (filterNoProcess) {
189-
return result.filter {
190-
getPackageInfoWithComponents(
191-
it.packageName, MATCH_ALL_FLAGS, it.applicationInfo!!.uid / PER_USER_RANGE)
192-
?.fetchProcesses()
193-
?.isNotEmpty() == true
194-
}
243+
return result
244+
.parallelStream()
245+
.filter {
246+
getPackageInfoWithComponents(
247+
it.packageName, MATCH_ALL_FLAGS, it.applicationInfo!!.uid / PER_USER_RANGE)
248+
?.fetchProcesses()
249+
?.isNotEmpty() == true
250+
}
251+
.collect(Collectors.toList())
195252
}
253+
196254
return result
197255
}
198256

0 commit comments

Comments
 (0)