{"record":{"id":"bd74fc8d3209fe87","repo":"microg/GmsCore","slug":"suggested-pid","errorCode":null,"errorMessage":"suggested PID [","messagePattern":"suggested PID \\[","errorType":"validation","errorClass":"SecurityException","httpStatus":null,"severity":"error","filePath":"play-services-base/core/src/main/java/org/microg/gms/common/PackageUtils.java","lineNumber":234,"sourceCode":"\n    @Nullable\n    public static String getAndCheckCallingPackage(@NonNull Context context, int suggestedCallerUid) {\n        return getAndCheckCallingPackage(context, null, suggestedCallerUid);\n    }\n\n    @Nullable\n    public static String getAndCheckCallingPackage(@NonNull Context context, @Nullable String suggestedPackageName, int suggestedCallerUid) {\n        return getAndCheckCallingPackage(context, suggestedPackageName, suggestedCallerUid, 0);\n    }\n\n    @Nullable\n    public static String getAndCheckCallingPackage(@NonNull Context context, @Nullable String suggestedPackageName, int suggestedCallerUid, int suggestedCallerPid) {\n        int callingUid = Binder.getCallingUid(), callingPid = Binder.getCallingPid();\n        if (suggestedCallerUid > 0 && suggestedCallerUid != callingUid) {\n            throw new SecurityException(\"suggested UID [\" + suggestedCallerUid + \"] and real calling UID [\" + callingUid + \"] mismatch!\");\n        }\n        if (suggestedCallerPid > 0 && suggestedCallerPid != callingPid) {\n            throw new SecurityException(\"suggested PID [\" + suggestedCallerPid + \"] and real calling PID [\" + callingPid + \"] mismatch!\");\n        }\n        return getAndCheckPackage(context, suggestedPackageName, callingUid, callingPid);\n    }\n\n    @Nullable\n    public static String getAndCheckPackage(Context context, String suggestedPackageName, int callingUid) {\n        return getAndCheckPackage(context, suggestedPackageName, callingUid, 0);\n    }\n\n    @Nullable\n    public static String getAndCheckPackage(@NonNull Context context, @Nullable String suggestedPackageName, int callingUid, int callingPid) {\n        String packageName = packageFromProcessId(context, callingPid);\n        if (packageName == null) {\n            String[] packagesForUid = context.getPackageManager().getPackagesForUid(callingUid);\n            if (packagesForUid != null && packagesForUid.length != 0) {\n                if (packagesForUid.length == 1) {\n                    packageName = packagesForUid[0];\n                } else if (Arrays.asList(packagesForUid).contains(suggestedPackageName)) {","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-base/core/src/main/java/org/microg/gms/common/PackageUtils.java#L216-L252","documentation":"Same guard as the UID check, but for the process id: if suggestedCallerPid > 0 and differs from Binder.getCallingPid(), getAndCheckCallingPackage throws this SecurityException. It prevents misattributed or spoofed caller identity during package-name verification.","triggerScenarios":"Passing a caller PID captured in a previous transaction (PIDs change per process) or taken from client-controlled extras, so it no longer matches the current Binder.getCallingPid(); calling the method from a different thread/process than where the PID was sampled.","commonSituations":"Sticky cached caller info reused across binder calls; proxy services replaying stored uid/pid pairs; refactored code that now runs in a worker process.","solutions":["Pass suggestedCallerPid = 0 to skip the PID check, or use the overload that derives identity from Binder automatically.","Always sample Binder.getCallingPid()/getCallingUid() at call time in the same transaction; never cache or forward them across calls.","Remove pid/uid fields from any client-provided request data used for this check.","Log both values on mismatch to find which component is sending stale identity data."],"exampleFix":"// before\nint pid = request.getInt(\"callerPid\"); // stale\nPackageUtils.getAndCheckCallingPackage(context, pkg, uid, pid);\n\n// after\nPackageUtils.getAndCheckCallingPackage(context, pkg, uid, 0); // let Binder provide pid","handlingStrategy":"validation","validationCode":"int callingPid = Binder.getCallingPid();\nif (suggestedCallerPid > 0 && suggestedCallerPid != callingPid) {\n    throw new IllegalArgumentException(\"suggestedCallerPid does not match Binder caller\");\n}","typeGuard":"boolean isTrustedSuggestedPid(int suggestedPid) {\n    return suggestedPid <= 0 || suggestedPid == Binder.getCallingPid();\n}","tryCatchPattern":"try {\n    return PackageUtils.getAndCheckCallingPackage(context, suggestedPkg, uid, pid);\n} catch (SecurityException e) {\n    Log.w(TAG, \"Caller identity mismatch (pid)\", e);\n    return null;\n}","preventionTips":["Never reuse pid/uid captured in a previous transaction; PIDs are per-process and calls may hop processes.","Prefer the overloads that do not take explicit uid/pid.","Strip caller-pid fields from request data models.","Log Binder.getCallingPid() on mismatch to trace stale senders."],"tags":["android","binder","security","pid-mismatch"],"backgroundTag":"invalid-argument-value","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}