Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proper multi-user support #1349

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ dependencies {
implementation "com.github.topjohnwu.libsu:core:${libsuVersion}"
implementation "com.github.topjohnwu.libsu:service:${libsuVersion}"
implementation "com.github.topjohnwu.libsu:nio:${libsuVersion}"
implementation "org.lsposed.hiddenapibypass:hiddenapibypass:4.3"
compileOnly project(":hiddenapi:stubs")
implementation "eu.chainfire:libsuperuser:1.1.0"
implementation "com.github.ukanth:android-lockpattern:8.0.4"
implementation "com.afollestad.material-dialogs:core:0.9.6.0"
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@


<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission"/>
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>

<uses-permission
android:name="android.permission.FOREGROUND_SERVICE"/>
Expand Down Expand Up @@ -356,4 +357,4 @@
<activity android:name=".activity.CustomRulesActivity"></activity>
</application>

</manifest>
</manifest>
173 changes: 117 additions & 56 deletions app/src/main/java/dev/ukanth/ufirewall/Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
import javax.crypto.spec.DESKeySpec;

import dev.ukanth.ufirewall.MainActivity.GetAppList;
import dev.ukanth.ufirewall.MultiUser;
import dev.ukanth.ufirewall.log.Log;
import dev.ukanth.ufirewall.log.LogData;
import dev.ukanth.ufirewall.log.LogData_Table;
Expand Down Expand Up @@ -168,6 +169,7 @@ public final class Api {
public static final int NOTIFICATION_ID = 1;
public static final String PREF_FIREWALL_STATUS = "AFWallStaus";
public static final String DEFAULT_PREFS_NAME = "AFWallPrefs";
public static final String CACHE_PREFS_NAME = "AFWallCache";
//for import/export rules
//revertback to old approach for performance
public static final String PREF_3G_PKG_UIDS = "AllowedPKG3G_UIDS";
Expand Down Expand Up @@ -1395,55 +1397,63 @@ public static List<PackageInfoData> getApps(Context ctx, GetAppList appList) {
}
//revert back to old approach

//always use the defaul preferences to store cache value - reduces the application usage size
SharedPreferences cachePrefs = ctx.getSharedPreferences(DEFAULT_PREFS_NAME, Context.MODE_PRIVATE);
SharedPreferences cachePrefs = ctx.getSharedPreferences(CACHE_PREFS_NAME, Context.MODE_PRIVATE);

int count = 0;
try {
listOfUids = new ArrayList<>();
//this code will be executed on devices running ICS or later
final UserManager um = (UserManager) ctx.getSystemService(Context.USER_SERVICE);
List<UserHandle> list = um.getUserProfiles();

for (UserHandle user : list) {
Matcher m = p.matcher(user.toString());
if (m.find() && m.groupCount() > 0) {
int id = Integer.parseInt(m.group(1));
if (id > 0) {
listOfUids.add(id);
/*if(G.supportDual()) {
listOfUids = new ArrayList<>();
//this code will be executed on devices running ICS or later
final UserManager um = (UserManager) ctx.getSystemService(Context.USER_SERVICE);
List<UserHandle> list = um.getUserProfiles();

for (UserHandle user : list) {
Matcher m = p.matcher(user.toString());
if (m.find() && m.groupCount() > 0) {
int id = Integer.parseInt(m.group(1));
if (id > 0) {
listOfUids.add(id);
}
}
}
}
//use pm list packages -f -U --user 10
int pkgManagerFlags = PackageManager.GET_META_DATA;
// it's useless to iterate over uninstalled packages if we don't support multi-profile apps
if (G.supportDual()) {
pkgManagerFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
}
}*/
PackageManager pkgmanager = ctx.getPackageManager();
List<ApplicationInfo> installed = pkgmanager.getInstalledApplications(pkgManagerFlags);
List<PackageInfo> installed;
if (G.isMultiUser()) {
installed = MultiUser.getInstalledPackagesFromAllUsers(MultiUser.MATCH_ALL_METADATA);
} else {
int pkgManagerFlags = PackageManager.GET_META_DATA;
// it's useless to iterate over uninstalled packages if we don't support multi-profile apps
if (G.supportDual()) {
pkgManagerFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
}
installed = pkgmanager.getInstalledPackages(pkgManagerFlags);
}
SparseArray<PackageInfoData> syncMap = new SparseArray<>();
Editor edit = cachePrefs.edit();
boolean changed = false;
String name;
String cachekey;
String cacheLabel = "cache.label.";
PackageInfoData app;
ApplicationInfo apinfo;

Date install = new Date();
install.setTime(System.currentTimeMillis() - (180000));

SparseArray<PackageInfoData> multiUserAppsMap = new SparseArray<>();
HashMap<Integer, String> packagesForUser = new HashMap<>();
if(G.supportDual()) {
/*if(G.supportDual()) {
packagesForUser = getPackagesForUser(listOfUids);
}
}*/


for (PackageInfo pkginfo : installed) {
ApplicationInfo apinfo = pkginfo.applicationInfo;
if (apinfo == null) continue;

for (int i = 0; i < installed.size(); i++) {
//for (ApplicationInfo apinfo : installed) {
int user_id = MultiUser.applicationUserId(apinfo);
Log.d(TAG, "Processing app info: " + apinfo.packageName + " / user " + user_id + " / uid " + apinfo.uid);
count = count + 1;
apinfo = installed.get(i);

if (appList != null) {
appList.doProgress(count);
Expand All @@ -1456,11 +1466,15 @@ public static List<PackageInfoData> getApps(Context ctx, GetAppList appList) {
continue;
}
// try to get the application label from our cache - getApplicationLabel() is horribly slow!!!!
cachekey = cacheLabel + apinfo.packageName;
cachekey = cacheLabel + apinfo.packageName + Integer.toString(user_id);
name = prefs.getString(cachekey, "");
if (name.length() == 0 || isRecentlyInstalled(apinfo.packageName)) {
// get label and put on cache
name = pkgmanager.getApplicationLabel(apinfo).toString();
if (G.isMultiUser()) {
name = pkgmanager.getApplicationLabel(apinfo).toString() + " / user " + Integer.toString(user_id);
} else {
name = pkgmanager.getApplicationLabel(apinfo).toString();
}
edit.putString(cachekey, name);
changed = true;
firstseen = true;
Expand All @@ -1480,8 +1494,7 @@ public static List<PackageInfoData> getApps(Context ctx, GetAppList appList) {
app.appType = 0;
}
app.pkgName = apinfo.packageName;
if ((apinfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0)
syncMap.put(apinfo.uid, app);
syncMap.put(app.uid, app);
} else {
app.names.add(name);
}
Expand Down Expand Up @@ -1509,12 +1522,12 @@ public static List<PackageInfoData> getApps(Context ctx, GetAppList appList) {
if (G.enableTor() && !app.selected_tor && Collections.binarySearch(selected_tor, app.uid) >= 0) {
app.selected_tor = true;
}
if (G.supportDual()) {
/*if (G.supportDual()) {
checkPartOfMultiUser(apinfo, name, listOfUids, packagesForUser, multiUserAppsMap);
}
}*/
}

if (G.supportDual()) {
/*if (G.supportDual()) {
//run through multi user map
for (int i = 0; i < multiUserAppsMap.size(); i++) {
app = multiUserAppsMap.valueAt(i);
Expand All @@ -1541,7 +1554,7 @@ public static List<PackageInfoData> getApps(Context ctx, GetAppList appList) {
}
syncMap.put(app.uid, app);
}
}
}*/

List<PackageInfoData> specialData = getSpecialData();

Expand Down Expand Up @@ -1636,7 +1649,7 @@ public static List<PackageInfoData> getSpecialData() {
return specialData;
}

private static void checkPartOfMultiUser(ApplicationInfo apinfo, String name, List<Integer> uid1, HashMap<Integer,String> pkgs, SparseArray<PackageInfoData> syncMap) {
/*private static void checkPartOfMultiUser(ApplicationInfo apinfo, String name, List<Integer> uid1, HashMap<Integer,String> pkgs, SparseArray<PackageInfoData> syncMap) {
try {
for (Integer integer : uid1) {
int appUid = Integer.parseInt(integer + "" + apinfo.uid + "");
Expand Down Expand Up @@ -1666,7 +1679,7 @@ private static void checkPartOfMultiUser(ApplicationInfo apinfo, String name, Li
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
}
}*/

private static boolean packagesExistForUserUid(HashMap<Integer,String> pkgs, int appUid) {
if(pkgs.containsKey(appUid)){
Expand Down Expand Up @@ -2357,16 +2370,36 @@ private static Map<String, JSONObject> getCurrentRulesAsMap(Context ctx) {
Map<String, JSONObject> exportMap = new HashMap<>();

try {
for (PackageInfoData app : apps) {
if (app.selected_wifi || app.selected_3g || app.selected_roam || app.selected_vpn ||
app.selected_tether || app.selected_lan || app.selected_tor) {
updateExportPackage(exportMap, app.pkgName, WIFI_EXPORT);
updateExportPackage(exportMap, app.pkgName, DATA_EXPORT);
updateExportPackage(exportMap, app.pkgName, ROAM_EXPORT);
updateExportPackage(exportMap, app.pkgName, VPN_EXPORT);
updateExportPackage(exportMap, app.pkgName, TETHER_EXPORT);
updateExportPackage(exportMap, app.pkgName, LAN_EXPORT);
updateExportPackage(exportMap, app.pkgName, TOR_EXPORT);
for (int i = 0; i < apps.size(); i++) {
PackageInfoData pkginfo = apps.get(i);
String packageName = pkginfo.pkgName;
if (G.isMultiUser()) {
int user_id = MultiUser.applicationUserId(pkginfo.appinfo);
if (user_id > 0) {
packageName = packageName + "/" + String.valueOf(user_id);
}
}

if (apps.get(i).selected_wifi) {
updateExportPackage(exportMap, packageName, WIFI_EXPORT);
}
if (apps.get(i).selected_3g) {
updateExportPackage(exportMap, packageName, DATA_EXPORT);
}
if (apps.get(i).selected_roam) {
updateExportPackage(exportMap, packageName, ROAM_EXPORT);
}
if (apps.get(i).selected_vpn) {
updateExportPackage(exportMap, packageName, VPN_EXPORT);
}
if (apps.get(i).selected_tether) {
updateExportPackage(exportMap, packageName, TETHER_EXPORT);
}
if (apps.get(i).selected_lan) {
updateExportPackage(exportMap, packageName, LAN_EXPORT);
}
if (apps.get(i).selected_tor) {
updateExportPackage(exportMap, packageName, TOR_EXPORT);
}
}
} catch (JSONException e) {
Expand Down Expand Up @@ -2596,10 +2629,19 @@ private static void updateRulesFromJson(Context ctx, JSONObject object, String p
uidBuilders[TOR_EXPORT] = new StringBuilder();

Map<String, Object> json = JsonHelper.toMap(object);
Map<String, PackageInfoData> muPackages = null;
final PackageManager pm = ctx.getPackageManager();

for (Map.Entry<String, Object> entry : json.entrySet()) {
String pkgName = entry.getKey();
int user_id = 0;
if (G.isMultiUser()) {
if (pkgName.contains("/")) {
String[] parts = pkgName.split("/");
pkgName = parts[0];
user_id = Integer.parseInt(parts[1]);
}
}
if (pkgName.contains(":")) {
pkgName = pkgName.split(":")[0];
}
Expand All @@ -2618,10 +2660,30 @@ private static void updateRulesFromJson(Context ctx, JSONObject object, String p
if (pkgName.startsWith("dev.afwall.special")) {
uidBuilder.append(specialApps.get(pkgName));
} else {
try {
uidBuilder.append(pm.getApplicationInfo(pkgName, 0).uid);
} catch (NameNotFoundException e) {
// Handle exception if needed
if (user_id > 0) {
if (muPackages == null) {
// build cache of all installed packages
muPackages = new HashMap();
List<PackageInfoData> apps = getApps(ctx, null);
for (PackageInfoData pkginfo : apps) {
int user_id_ = MultiUser.applicationUserId(pkginfo.appinfo);
if (user_id_ > 0) {
muPackages.put(pkginfo.pkgName + "/" + String.valueOf(user_id_), pkginfo);
}
}
}
PackageInfoData pkginfo = muPackages.get(pkgName + "/" + String.valueOf(user_id));
if (pkginfo != null) {
uidBuilder.append(pkginfo.uid);
} else {
// Handle not found if needed
}
} else {
try {
uidBuilder.append(pm.getApplicationInfo(pkgName, 0).uid);
} catch (NameNotFoundException e) {
// Handle exception if needed
}
}
}
}
Expand Down Expand Up @@ -2755,7 +2817,7 @@ public static boolean loadSharedPreferencesFromFile(Context ctx, StringBuilder b
public static void probeLogTarget(final Context ctx) {

}

@SuppressLint("InlinedApi")
public static void showInstalledAppDetails(Context context, String packageName) {
final String SCHEME = "package";
Expand Down Expand Up @@ -3263,7 +3325,7 @@ public static final class PackageInfoData {
public String pkgName;

/**
* Application Type
* Application Type. 0 for system, 1 for user, 2 for core.
*/
public int appType;

Expand Down Expand Up @@ -3379,13 +3441,12 @@ public String toString() {
public String toStringWithUID() {
if (tostr == null) {
StringBuilder s = new StringBuilder();
s.append("[ ");
s.append(uid);
s.append(" ] ");
for (int i = 0; i < names.size(); i++) {
if (i != 0) s.append(", ");
s.append(names.get(i));
}
s.append(" / ");
s.append(uid);
s.append("\n");
tostr = s.toString();
}
Expand Down
7 changes: 6 additions & 1 deletion app/src/main/java/dev/ukanth/ufirewall/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import dev.ukanth.ufirewall.activity.OldLogActivity;
import dev.ukanth.ufirewall.activity.RulesActivity;
import dev.ukanth.ufirewall.log.Log;
import dev.ukanth.ufirewall.MultiUser;
import dev.ukanth.ufirewall.preferences.PreferencesActivity;
import dev.ukanth.ufirewall.profiles.ProfileData;
import dev.ukanth.ufirewall.profiles.ProfileHelper;
Expand Down Expand Up @@ -233,6 +234,7 @@ public void onCreate(Bundle savedInstanceState) {
startRootShell();
new SecurityUtil(MainActivity.this).passCheck();
registerNetworkObserver();
MultiUser.setup();
}
registerUIbroadcast4();
registerUIbroadcast6();
Expand Down Expand Up @@ -997,8 +999,11 @@ private void showApplications(final String searchStr) {
for (PackageInfoData app : apps) {
for (String str : app.names) {
if (str != null && searchStr != null) {
if (unique.contains(app.uid)) {
continue;
}
if (str.contains(searchStr.toLowerCase()) || str.toLowerCase().contains(searchStr.toLowerCase())
&& !searchApp.contains(app) || (G.showUid() && (str + " " + app.uid).contains(searchStr) && !unique.contains(app.uid))) {
&& !searchApp.contains(app) || (G.showUid() && (str + " " + app.uid).contains(searchStr))) {
searchApp.add(app);
unique.add(app.uid);
isResultsFound = true;
Expand Down
Loading
Loading