vpnhide/kmod/module/service.sh
okhsunrog 16578a15d2 feat: target apps across all user profiles (work profile, etc.)
Android user profiles (work profile, MIUI Second Space, Private Space,
secondary users) each give the same package its own UID in the
namespace `<user>*100000 + <app_id>`. Previously every pkg→UID
resolver used plain `pm list packages -U`, which only emits UIDs for
the primary user, so the work-profile copy of Telegram kept seeing
the VPN even though the user had marked Telegram as a target.

Switch every resolver to `pm list packages -U --user all`. The pm
output format for multi-profile apps is comma-separated on one line:

    package:com.android.chrome uid:10187,1010187

Each call site now splits on `,` and emits one UID per line so every
profile's copy is individually matched by the hooks. No UI changes —
"mark Telegram as a target" just now means "in every profile it's
installed in".

Resolvers touched (all places found by an audit, no duplicates left):

  Shell (boot-time):
    kmod/module/service.sh
    zygisk/module/service.sh
    portshide/module/vpnhide_ports_apply.sh

  Kotlin (save-time via suExec):
    AppPickerScreen.kt       — buildUidResolver
    AppHidingScreen.kt       — buildHidingUidResolver
    ShellUtils.kt            — ensureSelfInTargets
    TargetsCache.kt          — PM_LIST batch script + parser

Verified on a Pixel 4a with a managed profile (user 10):
  - Chrome toggled in LZ on primary → both 10187 and 1010187 land in
    /data/system/vpnhide_uids.txt.
  - Primary-only apps (Ozon, etc.) still resolve to a single UID.
  - ensureSelfInTargets correctly adds both UIDs when vpnhide is
    installed across profiles.
2026-04-20 01:27:11 +03:00

99 lines
3.7 KiB
Bash

#!/system/bin/sh
# Resolves package names → UIDs for kmod and lsposed at boot.
# kmod targets → /proc/vpnhide_targets
# lsposed targets → /data/system/vpnhide_uids.txt
KMOD_TARGETS="/data/adb/vpnhide_kmod/targets.txt"
LSPOSED_TARGETS="/data/adb/vpnhide_lsposed/targets.txt"
PROC_TARGETS="/proc/vpnhide_targets"
SS_UIDS_FILE="/data/system/vpnhide_uids.txt"
# Wait for the proc entry (kernel module must be loaded)
for i in 1 2 3 4 5 6 7 8 9 10; do
[ -f "$PROC_TARGETS" ] && break
sleep 1
done
# Wait until PackageManager has actually indexed user-installed apps.
# `pm list packages` starts responding very early in boot but returns
# only system packages for several more seconds — if we resolve during
# that window, `dev.okhsunrog.vpnhide` (and any other user-installed
# target) silently drops from the UID file and the LSPosed hook caches
# an empty target set for the rest of the session. Gate on our own
# package being visible, with a 60s budget.
for i in $(seq 1 60); do
if pm list packages -U 2>/dev/null | grep -q "^package:dev.okhsunrog.vpnhide "; then
break
fi
sleep 1
done
if [ ! -f "$PROC_TARGETS" ]; then
log -t vpnhide "kernel module not loaded, skipping kmod UID resolution"
fi
# Migration: if lsposed targets don't exist yet, seed from kmod targets
if [ ! -f "$LSPOSED_TARGETS" ] && [ -f "$KMOD_TARGETS" ]; then
cp "$KMOD_TARGETS" "$LSPOSED_TARGETS"
log -t vpnhide "migrated kmod targets to lsposed targets"
fi
# Get all packages with UIDs across every profile in one call.
# `--user all` emits comma-separated UIDs per package line for apps
# present in multiple profiles, e.g.
# package:com.android.chrome uid:10187,1010187
# so work-profile / secondary-user installs get targeted too.
ALL_PACKAGES="$(pm list packages -U --user all 2>/dev/null)"
# resolve_uids <targets_file> — prints one UID per line to stdout.
# Splits the comma-separated UID list so every profile's copy of the
# target package ends up individually in /proc/vpnhide_targets.
resolve_uids() {
local targets_file="$1"
[ -f "$targets_file" ] || return
local uids=""
while IFS= read -r line || [ -n "$line" ]; do
pkg="$(echo "$line" | tr -d '[:space:]')"
[ -z "$pkg" ] && continue
case "$pkg" in \#*) continue ;; esac
uid_csv="$(echo "$ALL_PACKAGES" | grep "^package:${pkg} " | sed 's/.*uid://')"
if [ -n "$uid_csv" ]; then
expanded="$(echo "$uid_csv" | tr ',' '\n')"
if [ -z "$uids" ]; then uids="$expanded"; else uids="${uids}
${expanded}"; fi
else
log -t vpnhide "package not found: $pkg"
fi
done < "$targets_file"
[ -n "$uids" ] && echo "$uids"
}
# Resolve kmod targets → /proc/vpnhide_targets
if [ -f "$PROC_TARGETS" ] && [ -f "$KMOD_TARGETS" ]; then
KMOD_UIDS="$(resolve_uids "$KMOD_TARGETS")"
if [ -n "$KMOD_UIDS" ]; then
echo "$KMOD_UIDS" > "$PROC_TARGETS"
count="$(echo "$KMOD_UIDS" | wc -l)"
log -t vpnhide "kmod: loaded $count target UIDs"
else
log -t vpnhide "kmod: no UIDs resolved"
fi
fi
# Resolve lsposed targets → /data/system/vpnhide_uids.txt
# Create persist dir if needed (for first-time installs)
mkdir -p /data/adb/vpnhide_lsposed 2>/dev/null
if [ -f "$LSPOSED_TARGETS" ]; then
LSPOSED_UIDS="$(resolve_uids "$LSPOSED_TARGETS")"
if [ -n "$LSPOSED_UIDS" ]; then
echo "$LSPOSED_UIDS" > "$SS_UIDS_FILE"
chmod 644 "$SS_UIDS_FILE"
chcon u:object_r:system_data_file:s0 "$SS_UIDS_FILE" 2>/dev/null
count="$(echo "$LSPOSED_UIDS" | wc -l)"
log -t vpnhide "lsposed: wrote $count UIDs to $SS_UIDS_FILE"
else
echo > "$SS_UIDS_FILE"
chmod 644 "$SS_UIDS_FILE"
log -t vpnhide "lsposed: no UIDs resolved"
fi
fi