microg/GmsCore · error · SecurityException
suggested UID [
Error message
suggested UID [
What it means
getAndCheckCallingPackage verifies that a caller-supplied 'suggested' caller identity matches the real Binder identity. If suggestedCallerUid > 0 and differs from Binder.getCallingUid(), it throws this SecurityException. The library does this to prevent a privileged or IPC-forwarding process from spoofing another app's identity when claiming a package name.
Source
Thrown at play-services-base/core/src/main/java/org/microg/gms/common/PackageUtils.java:231
throw e;
}
}
@Nullable
public static String getAndCheckCallingPackage(@NonNull Context context, int suggestedCallerUid) {
return getAndCheckCallingPackage(context, null, suggestedCallerUid);
}
@Nullable
public static String getAndCheckCallingPackage(@NonNull Context context, @Nullable String suggestedPackageName, int suggestedCallerUid) {
return getAndCheckCallingPackage(context, suggestedPackageName, suggestedCallerUid, 0);
}
@Nullable
public static String getAndCheckCallingPackage(@NonNull Context context, @Nullable String suggestedPackageName, int suggestedCallerUid, int suggestedCallerPid) {
int callingUid = Binder.getCallingUid(), callingPid = Binder.getCallingPid();
if (suggestedCallerUid > 0 && suggestedCallerUid != callingUid) {
throw new SecurityException("suggested UID [" + suggestedCallerUid + "] and real calling UID [" + callingUid + "] mismatch!");
}
if (suggestedCallerPid > 0 && suggestedCallerPid != callingPid) {
throw new SecurityException("suggested PID [" + suggestedCallerPid + "] and real calling PID [" + callingPid + "] mismatch!");
}
return getAndCheckPackage(context, suggestedPackageName, callingUid, callingPid);
}
@Nullable
public static String getAndCheckPackage(Context context, String suggestedPackageName, int callingUid) {
return getAndCheckPackage(context, suggestedPackageName, callingUid, 0);
}
@Nullable
public static String getAndCheckPackage(@NonNull Context context, @Nullable String suggestedPackageName, int callingUid, int callingPid) {
String packageName = packageFromProcessId(context, callingPid);
if (packageName == null) {
String[] packagesForUid = context.getPackageManager().getPackagesForUid(callingUid);
if (packagesForUid != null && packagesForUid.length != 0) {View on GitHub (pinned to 157c9d86ac)
Solutions
- Pass suggestedCallerUid = 0 (or use the overload without uid/pid) unless you obtained the value from a trusted source for this exact transaction.
- Compare against Binder.getCallingUid() yourself and log the mismatch before calling, to identify the spoofing client.
- If you intentionally forward on behalf of another process, do not forward its UID; perform the package check with the real calling UID.
- Fix client code to stop sending uid/pid fields in the request bundle.
Example fix
// before
String pkg = PackageUtils.getAndCheckCallingPackage(context, suggestedPkg, extra.getInt("uid"), extra.getInt("pid"));
// after
String pkg = PackageUtils.getAndCheckCallingPackage(context, suggestedPkg); // uid/pid taken from Binder Defensive patterns
Strategy: validation
Validate before calling
int callingUid = Binder.getCallingUid();
if (suggestedCallerUid > 0 && suggestedCallerUid != callingUid) {
throw new IllegalArgumentException("suggestedCallerUid does not match Binder caller");
} Type guard
boolean isTrustedSuggestedUid(int suggestedUid) {
return suggestedUid <= 0 || suggestedUid == Binder.getCallingUid();
} Try / catch
try {
return PackageUtils.getAndCheckCallingPackage(context, suggestedPkg, uid, pid);
} catch (SecurityException e) {
Log.w(TAG, "Caller identity mismatch (uid)", e);
return null;
} Prevention
- Pass 0 for suggestedCallerUid unless it comes from a trusted in-transaction source.
- Never echo uid/pid from client-supplied extras back into the check.
- Sample Binder identity at call time, never cache it.
- Audit AIDL entry points for forwarded identity fields.
When it happens
Trigger: An IPC endpoint (e.g. an AIDL service method receiving a Bundle) passes suggestedCallerUid from untrusted client input that does not equal Binder.getCallingUid(); forwarding a request on behalf of another process while passing that process's UID.
Common situations: Hand-written AIDL glue code that copies a UID/PID out of the request extras instead of leaving it 0; proxy/dispatcher apps forwarding calls to microG services; stale code written for non-Binder call paths.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- suggested PID [
- Access denied, missing google package permission for
- UID [
- No fields were found
- Too many non-synthetic fields were found
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/d1f8e58d2270c684.
Report an issue: GitHub.