5555import java .io .InputStreamReader ;
5656import java .lang .reflect .Constructor ;
5757import java .lang .reflect .InvocationTargetException ;
58+ import java .lang .reflect .Method ;
5859import java .util .ArrayList ;
5960import java .util .Collections ;
6061import java .util .HashMap ;
@@ -73,11 +74,49 @@ public class PackageService {
7374 static final int INSTALL_REASON_UNKNOWN = 0 ;
7475 static final int MATCH_ANY_USER = 0x00400000 ; // PackageManager.MATCH_ANY_USER
7576
76- static final int MATCH_ALL_FLAGS = PackageManager .MATCH_DISABLED_COMPONENTS | PackageManager .MATCH_DIRECT_BOOT_AWARE | PackageManager .MATCH_DIRECT_BOOT_UNAWARE | PackageManager .MATCH_UNINSTALLED_PACKAGES | MATCH_ANY_USER ;
77+ static final int MATCH_ALL_FLAGS = PackageManager .MATCH_DISABLED_COMPONENTS | PackageManager .MATCH_DIRECT_BOOT_AWARE
78+ | PackageManager .MATCH_DIRECT_BOOT_UNAWARE | PackageManager .MATCH_UNINSTALLED_PACKAGES | MATCH_ANY_USER ;
7779 public static final int PER_USER_RANGE = 100000 ;
7880
7981 private static IPackageManager pm = null ;
8082 private static IBinder binder = null ;
83+ private static final Method getInstalledPackagesMethod ;
84+
85+ static {
86+ Method method = null ;
87+ try {
88+ boolean isLongFlags = Build .VERSION .SDK_INT >= Build .VERSION_CODES .TIRAMISU ;
89+ Class <?> flagsType = isLongFlags ? long .class : int .class ;
90+
91+ for (Method m : IPackageManager .class .getDeclaredMethods ()) {
92+ if (m .getName ().equals ("getInstalledPackages" ) &&
93+ m .getParameterTypes ().length == 2 &&
94+ m .getParameterTypes ()[0 ] == flagsType ) {
95+ m .setAccessible (true );
96+ method = m ;
97+ break ;
98+ }
99+ }
100+ } catch (Exception e ) {
101+ Log .e ("PackageManagerUtils" , "Failed to find getInstalledPackages method" , e );
102+ }
103+ getInstalledPackagesMethod = method ;
104+ }
105+
106+ private static List <PackageInfo > getInstalledPackagesReflect (IPackageManager pm , Object flags , int userId ) {
107+ if (getInstalledPackagesMethod == null || pm == null )
108+ return Collections .emptyList ();
109+ try {
110+ Object result = getInstalledPackagesMethod .invoke (pm , flags , userId );
111+ if (result instanceof ParceledListSlice ) {
112+ // noinspection unchecked
113+ return ((ParceledListSlice <PackageInfo >) result ).getList ();
114+ }
115+ } catch (Exception e ) {
116+ Log .w ("PackageManagerUtils" , "Reflection call failed" , e );
117+ }
118+ return Collections .emptyList ();
119+ }
81120
82121 static boolean isAlive () {
83122 var pm = getPackageManager ();
@@ -141,21 +180,20 @@ public static ApplicationInfo getApplicationInfo(String packageName, int flags,
141180 }
142181
143182 // Only for manager
144- public static ParcelableListSlice <PackageInfo > getInstalledPackagesFromAllUsers (int flags , boolean filterNoProcess ) throws RemoteException {
183+ public static ParcelableListSlice <PackageInfo > getInstalledPackagesFromAllUsers (int flags , boolean filterNoProcess )
184+ throws RemoteException {
145185 List <PackageInfo > res = new ArrayList <>();
146186 IPackageManager pm = getPackageManager ();
147- if (pm == null ) return ParcelableListSlice .emptyList ();
187+ if (pm == null )
188+ return ParcelableListSlice .emptyList ();
189+ // Prepare flags once outside the loop
190+ Object flagsObj = (Build .VERSION .SDK_INT >= Build .VERSION_CODES .TIRAMISU ) ? (long ) flags : flags ;
148191 for (var user : UserService .getUsers ()) {
149- // in case pkginfo of other users in primary user
150- ParceledListSlice <PackageInfo > infos ;
151- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .TIRAMISU ) {
152- infos = pm .getInstalledPackages ((long ) flags , user .id );
153- } else {
154- infos = pm .getInstalledPackages (flags , user .id );
155- }
156- res .addAll (infos
157- .getList ().parallelStream ()
158- .filter (info -> info .applicationInfo != null && info .applicationInfo .uid / PER_USER_RANGE == user .id )
192+ // Use the reflective helper instead of direct AIDL calls
193+ List <PackageInfo > infos = getInstalledPackagesReflect (pm , flagsObj , user .id );
194+ res .addAll (infos .parallelStream ()
195+ .filter (info -> info .applicationInfo != null
196+ && info .applicationInfo .uid / PER_USER_RANGE == user .id )
159197 .filter (info -> {
160198 try {
161199 return isPackageAvailable (info .packageName , user .id , true );
0 commit comments