asLody/VirtualApp · error · SecurityException
Invalid userId
Error message
Invalid userId
What it means
VPackageManagerService.checkUserId() validates that the target user profile exists via VUserManagerService.get().exists(userId). Package/component lookups are per-user in VirtualApp; querying a userId that was never created throws SecurityException("Invalid userId "+userId) instead of returning null data.
Solutions
- Create/obtain a valid user via VUserManagerService (e.g. start/create user) and pass its id to package lookups.
- Before calling, guard with VUserManagerService.get().exists(userId) and fall back to a valid user id.
- Replace hardcoded userId (especially 0) with the id of the currently active virtual user.
- Handle user removal: refresh cached userIds and retry after the user is recreated.
Example fix
// before
PackageInfo pi = vPms.getPackageInfo(pkg, 0, 0); // userId 0 may not exist
// after
int userId = VUserManagerService.get().exists(0) ? 0 : VUserManagerService.get().getUsers().get(0).id;
if (!VUserManagerService.get().exists(userId)) { userId = vUserManager.createUser("user").id; }
PackageInfo pi = vPms.getPackageInfo(pkg, 0, userId); Defensive patterns
Strategy: validation
Validate before calling
if (!VUserManagerService.get().exists(userId)) {
// pick a valid user or create one before any package lookup
userId = VUserManagerService.get().getUsers().get(0).id;
} Type guard
boolean isValidVirtualUser(int userId) {
return VUserManagerService.get() != null && VUserManagerService.get().exists(userId);
} Try / catch
try {
return vPms.getPackageInfo(packageName, flags, userId);
} catch (SecurityException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Invalid userId")) {
return vPms.getPackageInfo(packageName, flags, getDefaultVirtualUserId());
}
throw e;
} Prevention
- Never hardcode userId (especially 0); resolve the active virtual user at runtime.
- Refresh cached user ids after user creation/removal or host app reinstall.
- Guard every per-user PM lookup with VUserManagerService.get().exists(userId).
- Distinguish OS user ids from VirtualApp user ids in your code to avoid mixing the two namespaces.
When it happens
Trigger: Calling getPackageInfo, getActivityInfo, getReceiverInfo, getServiceInfo, getProviderInfo, or resolveIntent with a flags+userId where the userId is not an installed virtual user — e.g. userId 0 in a fresh VirtualApp install (only user 10+ typically exists), a stale cached userId after the user was removed, or an hardcoded user id.
Common situations: Hardcoding userId=0 in multi-user virtual setups; calling PM APIs after VUserManagerService users were wiped (reinstall of the host app); concurrent user removal while another thread performs a package lookup; passing an OS userId (e.g. from UserManager) instead of a VirtualApp user id.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Unable to create application
- Who are you?
- Failed to allocate session ID
- Invalid userId
- Unable to start receiver
AI-assisted analysis of asLody/VirtualApp@666fefcb5d (2026-09-09).
Data as JSON: /api/errors/b07874974308e27a.
Report an issue: GitHub.
Appendix: source
Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/server/pm/VPackageManagerService.java:279
private int updateFlagsNought(int flags) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return flags;
}
if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_DIRECT_BOOT_AWARE)) != 0) {
// Caller expressed an explicit opinion about what encryption
// aware/unaware components they want to see, so fall through and
// give them what they want
} else {
// Caller expressed no opinion, so match based on user state
flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
}
return flags;
}
private void checkUserId(int userId) {
if (!VUserManagerService.get().exists(userId)) {
throw new SecurityException("Invalid userId " + userId);
}
}
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
checkUserId(userId);
flags = updateFlagsNought(flags);
synchronized (mPackages) {
VPackage p = mPackages.get(component.getPackageName());
if (p != null) {
PackageSetting ps = (PackageSetting) p.mExtras;
VPackage.ActivityComponent a = mActivities.mActivities.get(component);
if (a != null) {
ActivityInfo activityInfo = PackageParserEx.generateActivityInfo(a, flags, ps.readUserState(userId), userId);
ComponentFixer.fixComponentInfo(ps, activityInfo, userId);
return activityInfo;
}
}View on GitHub (pinned to 666fefcb5d)