Skip to content

Commit 1d8fe53

Browse files
committed
WIP: proper multi-user support. works, but missing some app names and icons
1 parent 9a0864c commit 1d8fe53

3 files changed

Lines changed: 105 additions & 47 deletions

File tree

app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ android {
88
//applicationId "dev.ukanth.ufirewall.donate"
99
minSdkVersion 21
1010
targetSdkVersion 33
11-
versionCode 20230814
12-
versionName "3.6"
11+
versionCode 20230827
12+
versionName "3.6.1"
1313
//buildConfigField 'boolean', 'DONATE', 'true'
1414
}
1515

app/src/main/java/dev/ukanth/ufirewall/Api.java

Lines changed: 98 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,21 +1415,15 @@ public static List<PackageInfoData> getApps(Context ctx, GetAppList appList) {
14151415
}
14161416
}
14171417
//use pm list packages -f -U --user 10
1418-
int pkgManagerFlags = PackageManager.GET_META_DATA;
1419-
// it's useless to iterate over uninstalled packages if we don't support multi-profile apps
1420-
if (G.supportDual()) {
1421-
pkgManagerFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
1422-
}
1418+
int pkgManagerFlags = PackageManager.GET_META_DATA | PackageManager.GET_UNINSTALLED_PACKAGES;
14231419
PackageManager pkgmanager = ctx.getPackageManager();
1424-
List<ApplicationInfo> installed = pkgmanager.getInstalledApplications(pkgManagerFlags);
14251420
SparseArray<PackageInfoData> syncMap = new SparseArray<>();
14261421
Editor edit = cachePrefs.edit();
14271422
boolean changed = false;
14281423
String name;
14291424
String cachekey;
14301425
String cacheLabel = "cache.label.";
14311426
PackageInfoData app;
1432-
ApplicationInfo apinfo;
14331427

14341428
Date install = new Date();
14351429
install.setTime(System.currentTimeMillis() - (180000));
@@ -1440,48 +1434,57 @@ public static List<PackageInfoData> getApps(Context ctx, GetAppList appList) {
14401434
packagesForUser = getPackagesForUser(listOfUids);
14411435
}
14421436

1443-
for (int i = 0; i < installed.size(); i++) {
1444-
//for (ApplicationInfo apinfo : installed) {
1437+
//List<ApplicationInfo> installed = pkgmanager.getInstalledApplications(pkgManagerFlags);
1438+
/*List<PkgInfo> pkginfos = new ArrayList();
1439+
for (ApplicationInfo apinfo : installed) {
1440+
List<Integer> uids = new ArrayList();
1441+
String label = pkgmanager.getApplicationLabel(apinfo).toString();
1442+
uids.add(apinfo.uid);
1443+
pkginfos.add(new PkgInfo(apinfo.packageName, label, uids, apinfo.sourceDir, (apinfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0));
1444+
}*/
1445+
List<PkgInfo> pkginfos = getPackagesShell(pkgmanager);
1446+
1447+
for (PkgInfo pkg : pkginfos) {
1448+
Log.i(TAG, "Processing app info: " + pkg.packageName);
14451449
count = count + 1;
1446-
apinfo = installed.get(i);
14471450

14481451
if (appList != null) {
14491452
appList.doProgress(count);
14501453
}
14511454

14521455
boolean firstseen = false;
1453-
app = syncMap.get(apinfo.uid);
1456+
app = syncMap.get(pkg.uid);
14541457
// filter applications which are not allowed to access the Internet
1455-
if (app == null && PackageManager.PERMISSION_GRANTED != pkgmanager.checkPermission(Manifest.permission.INTERNET, apinfo.packageName) && !showAllApps()) {
1458+
// dumpsys package check-permission <package> android.permission.INTERNET <uid>
1459+
// contrary to help text, package goes first!
1460+
if (app == null && PackageManager.PERMISSION_GRANTED != pkgmanager.checkPermission(Manifest.permission.INTERNET, pkg.packageName) && !showAllApps()) {
14561461
continue;
14571462
}
14581463
// try to get the application label from our cache - getApplicationLabel() is horribly slow!!!!
1459-
cachekey = cacheLabel + apinfo.packageName;
1464+
cachekey = cacheLabel + pkg.packageName + Integer.toString(pkg.uid);
14601465
name = prefs.getString(cachekey, "");
1461-
if (name.length() == 0 || isRecentlyInstalled(apinfo.packageName)) {
1466+
if (name.length() == 0 || isRecentlyInstalled(pkg.packageName)) {
14621467
// get label and put on cache
1463-
name = pkgmanager.getApplicationLabel(apinfo).toString();
1468+
name = pkg.packageLabel + " / user " + Integer.toString(pkg.user_id);
14641469
edit.putString(cachekey, name);
14651470
changed = true;
14661471
firstseen = true;
14671472
}
14681473
if (app == null) {
14691474
app = new PackageInfoData();
1470-
app.uid = apinfo.uid;
1471-
app.installTime = new File(apinfo.sourceDir).lastModified();
1475+
app.uid = pkg.uid;
1476+
app.installTime = new File(pkg.sourceDir).lastModified();
14721477
app.names = new ArrayList<String>();
14731478
app.names.add(name);
1474-
app.appinfo = apinfo;
1475-
if (app.appinfo != null && (app.appinfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
1479+
if (!pkg.isSystem) {
14761480
//user app
14771481
app.appType = 1;
14781482
} else {
14791483
//system app
14801484
app.appType = 0;
14811485
}
1482-
app.pkgName = apinfo.packageName;
1483-
if ((apinfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0)
1484-
syncMap.put(apinfo.uid, app);
1486+
app.pkgName = pkg.packageName;
1487+
syncMap.put(app.uid, app);
14851488
} else {
14861489
app.names.add(name);
14871490
}
@@ -1509,12 +1512,12 @@ public static List<PackageInfoData> getApps(Context ctx, GetAppList appList) {
15091512
if (G.enableTor() && !app.selected_tor && Collections.binarySearch(selected_tor, app.uid) >= 0) {
15101513
app.selected_tor = true;
15111514
}
1512-
if (G.supportDual()) {
1515+
/*if (G.supportDual()) {
15131516
checkPartOfMultiUser(apinfo, name, listOfUids, packagesForUser, multiUserAppsMap);
1514-
}
1517+
}*/
15151518
}
15161519

1517-
if (G.supportDual()) {
1520+
/*if (G.supportDual()) {
15181521
//run through multi user map
15191522
for (int i = 0; i < multiUserAppsMap.size(); i++) {
15201523
app = multiUserAppsMap.valueAt(i);
@@ -1541,7 +1544,7 @@ public static List<PackageInfoData> getApps(Context ctx, GetAppList appList) {
15411544
}
15421545
syncMap.put(app.uid, app);
15431546
}
1544-
}
1547+
}*/
15451548

15461549
List<PackageInfoData> specialData = getSpecialData();
15471550

@@ -1636,7 +1639,7 @@ public static List<PackageInfoData> getSpecialData() {
16361639
return specialData;
16371640
}
16381641

1639-
private static void checkPartOfMultiUser(ApplicationInfo apinfo, String name, List<Integer> uid1, HashMap<Integer,String> pkgs, SparseArray<PackageInfoData> syncMap) {
1642+
/*private static void checkPartOfMultiUser(ApplicationInfo apinfo, String name, List<Integer> uid1, HashMap<Integer,String> pkgs, SparseArray<PackageInfoData> syncMap) {
16401643
try {
16411644
for (Integer integer : uid1) {
16421645
int appUid = Integer.parseInt(integer + "" + apinfo.uid + "");
@@ -1666,7 +1669,7 @@ private static void checkPartOfMultiUser(ApplicationInfo apinfo, String name, Li
16661669
} catch (Exception e) {
16671670
Log.e(TAG, e.getMessage(), e);
16681671
}
1669-
}
1672+
}*/
16701673

16711674
private static boolean packagesExistForUserUid(HashMap<Integer,String> pkgs, int appUid) {
16721675
if(pkgs.containsKey(appUid)){
@@ -1694,6 +1697,52 @@ public static HashMap<Integer, String> getPackagesForUser(List<Integer> userProf
16941697
return listApps.size() > 0 ? listApps : null;
16951698
}
16961699

1700+
private static final Pattern pmfU = Pattern.compile("package:(.*)=(.*?) uid:(.*)", Pattern.MULTILINE);
1701+
1702+
public static List<PkgInfo> pkgInfoFromPm(PackageManager mgr, String item, boolean isSystem) {
1703+
List<PkgInfo> infos = new ArrayList();
1704+
Matcher matcher = pmfU.matcher(item);
1705+
if (matcher.find() && matcher.groupCount() > 0) {
1706+
String sourceDir = matcher.group(1);
1707+
String packageName = matcher.group(2);
1708+
String packageLabel = null;
1709+
try {
1710+
ApplicationInfo info = mgr.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
1711+
packageLabel = mgr.getApplicationLabel(info).toString();
1712+
} catch (NameNotFoundException e) {
1713+
// test later for null
1714+
}
1715+
String[] uids = matcher.group(3).split(",");
1716+
for (String uid: uids) {
1717+
int uidi = Integer.parseInt(uid);
1718+
int user = uidi / 100000;
1719+
infos.add(new PkgInfo(packageName, (packageLabel == null)? packageName: packageLabel, uidi, user, sourceDir, isSystem));
1720+
}
1721+
} else {
1722+
Log.i(TAG, "could not parse pm output: " + item);
1723+
}
1724+
return infos;
1725+
}
1726+
1727+
public static List<PkgInfo> getPackagesShell(PackageManager mgr) {
1728+
List<PkgInfo> pkginfos = new ArrayList();
1729+
Shell.Result result;
1730+
List<String> out;
1731+
// user packages
1732+
result = Shell.cmd("pm list packages -f -U -3").exec();
1733+
out = result.getOut();
1734+
for (String item : out) {
1735+
pkginfos.addAll(pkgInfoFromPm(mgr, item, false));
1736+
}
1737+
// system packages
1738+
result = Shell.cmd("pm list packages -f -U -s").exec();
1739+
out = result.getOut();
1740+
for (String item : out) {
1741+
pkginfos.addAll(pkgInfoFromPm(mgr, item, true));
1742+
}
1743+
return pkginfos;
1744+
}
1745+
16971746
private static boolean isRecentlyInstalled(String packageName) {
16981747
boolean isRecent = false;
16991748
if (recentlyInstalled != null && recentlyInstalled.contains(packageName)) {
@@ -2755,7 +2804,7 @@ public static boolean loadSharedPreferencesFromFile(Context ctx, StringBuilder b
27552804
public static void probeLogTarget(final Context ctx) {
27562805

27572806
}
2758-
2807+
27592808
@SuppressLint("InlinedApi")
27602809
public static void showInstalledAppDetails(Context context, String packageName) {
27612810
final String SCHEME = "package";
@@ -3244,6 +3293,23 @@ protected Integer doInBackground(Object... params) {
32443293

32453294
}
32463295

3296+
public static final class PkgInfo {
3297+
public String packageName;
3298+
public String packageLabel;
3299+
public int uid; // uid for the app
3300+
public int user_id; // android user_id for the user
3301+
public String sourceDir;
3302+
public boolean isSystem;
3303+
public PkgInfo(String packageName, String packageLabel, int uid, int user_id, String sourceDir, boolean isSystem) {
3304+
this.packageName = packageName;
3305+
this.packageLabel = packageLabel;
3306+
this.uid = uid;
3307+
this.user_id = user_id;
3308+
this.sourceDir = sourceDir;
3309+
this.isSystem = isSystem;
3310+
}
3311+
}
3312+
32473313
/**
32483314
* Small structure to hold an application info
32493315
*/
@@ -3263,7 +3329,7 @@ public static final class PackageInfoData {
32633329
public String pkgName;
32643330

32653331
/**
3266-
* Application Type
3332+
* Application Type. 0 for system, 1 for user, 2 for core.
32673333
*/
32683334
public int appType;
32693335

@@ -3299,10 +3365,6 @@ public static final class PackageInfoData {
32993365
* toString cache
33003366
*/
33013367
public String tostr;
3302-
/**
3303-
* application info
3304-
*/
3305-
public ApplicationInfo appinfo;
33063368
/**
33073369
* cached application icon
33083370
*/
@@ -3350,9 +3412,6 @@ public boolean equals(Object o) {
33503412
@Override
33513413
public int hashCode() {
33523414
int result = 17;
3353-
if (appinfo != null) {
3354-
result = 31 * result + appinfo.hashCode();
3355-
}
33563415
result = 31 * result + uid;
33573416
result = 31 * result + pkgName.hashCode();
33583417
return result;
@@ -3379,13 +3438,12 @@ public String toString() {
33793438
public String toStringWithUID() {
33803439
if (tostr == null) {
33813440
StringBuilder s = new StringBuilder();
3382-
s.append("[ ");
3383-
s.append(uid);
3384-
s.append(" ] ");
33853441
for (int i = 0; i < names.size(); i++) {
33863442
if (i != 0) s.append(", ");
33873443
s.append(names.get(i));
33883444
}
3445+
s.append(" / ");
3446+
s.append(uid);
33893447
s.append("\n");
33903448
tostr = s.toString();
33913449
}

app/src/main/java/dev/ukanth/ufirewall/util/AppListArrayAdapter.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,11 @@ public View getView(final int position, View convertView, ViewGroup parent) {
144144
holder.text.setOnClickListener(v -> StartAppDetailActivityIntent(v,holder,id));
145145

146146

147-
ApplicationInfo info = holder.app.appinfo;
148-
if (info != null && (info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
147+
if (holder.app.appType == 1) {
149148
//user app
150149
holder.text.setTextColor(G.userColor());
151150
} else {
152-
//system app
151+
//system or core app
153152
holder.text.setTextColor(G.sysColor());
154153
}
155154

@@ -158,7 +157,7 @@ public View getView(final int position, View convertView, ViewGroup parent) {
158157
holder.icon.setImageDrawable(context.getDrawable(R.drawable.ic_unknown));
159158
} else {
160159
holder.icon.setImageDrawable(holder.app.cached_icon);
161-
if (!holder.app.icon_loaded && info != null) {
160+
if (!holder.app.icon_loaded) {
162161
// this icon has not been loaded yet - load it on a
163162
// separated thread
164163
try {
@@ -398,7 +397,8 @@ protected View doInBackground(Object... params) {
398397
final PackageManager pkgMgr = (PackageManager) params[1];
399398
final View viewToUpdate = (View) params[2];
400399
if (!app.icon_loaded) {
401-
Drawable d = new ScaleDrawable(pkgMgr.getApplicationIcon(app.appinfo), 0, 32, 32).getDrawable();
400+
ApplicationInfo info = pkgMgr.getApplicationInfo(app.pkgName, PackageManager.GET_UNINSTALLED_PACKAGES);
401+
Drawable d = new ScaleDrawable(pkgMgr.getApplicationIcon(info), 0, 32, 32).getDrawable();
402402
d.setBounds(0, 0, 32, 32);
403403
app.cached_icon = d;
404404
app.icon_loaded = true;

0 commit comments

Comments
 (0)