{"record":{"id":"aa16d2bbc9026ac0","repo":"microg/GmsCore","slug":"callingpackagename-does-not-have-google-games-acc","errorCode":null,"errorMessage":"$callingPackageName does not have google games access","messagePattern":"\\$callingPackageName does not have google games access","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"play-services-core/src/main/kotlin/org/microg/gms/games/FirstPartyGamesService.kt","lineNumber":37,"sourceCode":"import com.google.android.gms.games.client.IPlayGamesService\nimport com.google.android.gms.games.client.PlayGamesConsistencyTokens\nimport org.microg.gms.BaseService\nimport org.microg.gms.common.Constants\nimport org.microg.gms.common.GmsService\nimport org.microg.gms.common.GooglePackagePermission\nimport org.microg.gms.common.PackageUtils\nimport org.microg.gms.utils.warnOnTransactionIssues\n\nprivate const val TAG = \"PlayGamesService\"\nprivate val FIRST_PARTY_PACKAGES = setOf(Constants.GMS_PACKAGE_NAME, GAMES_PACKAGE_NAME)\n\nclass FirstPartyGamesService : BaseService(TAG, GmsService.GAMES) {\n    override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {\n        val packageName = PackageUtils.getAndCheckCallingPackageOrImpersonation(this, request.packageName)\n            ?: throw IllegalArgumentException(\"Missing package name\")\n        val callingPackageName = PackageUtils.getCallingPackage(this) ?: packageName\n        if (!PackageUtils.callerHasGooglePackagePermission(this, GooglePackagePermission.GAMES))\n            throw IllegalArgumentException(\"$callingPackageName does not have google games access\")\n        if (callingPackageName !in FIRST_PARTY_PACKAGES) throw IllegalArgumentException(\"$callingPackageName is not first-party\")\n        callback.onPostInitCompleteWithConnectionInfo(\n            CommonStatusCodes.SUCCESS,\n            PlayGamesServiceImpl(this, lifecycle, packageName),\n            ConnectionInfo()\n        )\n    }\n}\n\nclass PlayGamesServiceImpl(val context: Context, val lifecycle: Lifecycle, val packageName: String) : IPlayGamesService.Stub() {\n\n    override fun getGameCollection(callbacks: IPlayGamesCallbacks?, maxResults: Int, gameCollectionType: Int, z: Boolean, forceReload: Boolean) {\n        Log.d(TAG, \"Not yet implemented: getGameCollection($maxResults, $gameCollectionType, $z, $forceReload)\")\n        callbacks?.onData(DataHolder.empty(CommonStatusCodes.SUCCESS))\n    }\n\n    override fun loadGames(callbacks: IPlayGamesCallbacks?, playerId: String?, maxResults: Int, z: Boolean, forceReload: Boolean) {\n        Log.d(TAG, \"Not yet implemented: loadGames($playerId, $maxResults, $z, $forceReload)\")","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-core/src/main/kotlin/org/microg/gms/games/FirstPartyGamesService.kt#L19-L55","documentation":"FirstPartyGamesService is restricted to Google first-party apps: after resolving the caller it checks PackageUtils.callerHasGooglePackagePermission(GAMES) and throws IllegalArgumentException(\"<pkg> does not have google games access\") when the caller lacks that signature-based permission. This gate keeps the first-party Play Games implementation available only to Google-signed packages.","triggerScenarios":"Any non-Google-signed app binding to GmsService.GAMES through FirstPartyGamesService and reaching the permission check — its package name is interpolated into the message.","commonSituations":"A third-party game (or a modded/microG client like a custom Games client) connecting to the first-party endpoint instead of the regular GamesService/GamesConnectService; tests binding with a debug-signed app.","solutions":["Bind to the regular GamesService or GamesConnectService endpoints instead of FirstPartyGamesService","If you legitimately need first-party access, the calling package must be signed with a Google signature (not achievable for third parties)","For microG-based clients, use the impersonation path with a properly matching signature or the non-first-party service"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// caller-side check\nval isFirstParty = PackageUtils.callerHasGooglePackagePermission(context, GooglePackagePermission.GAMES)","typeGuard":null,"tryCatchPattern":"try {\n  firstPartyGamesClient.connect()\n} catch (e: IllegalArgumentException) {\n  if (e.message?.endsWith(\"does not have google games access\") == true) {\n    gamesConnectClient.connect() // fall back to public endpoint\n  }\n}","preventionTips":["Third-party apps must use GamesService or GamesConnectService, not FirstPartyGamesService","Do not attempt to bind first-party endpoints from debug-signed builds","Understand GooglePackagePermission is signature-based and cannot be granted to non-Google apps"],"tags":["play-games","permission-denied","first-party","service-binding"],"backgroundTag":"permission-denied","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}