{"record":{"id":"b45f73d9143bbbc2","repo":"microg/GmsCore","slug":"device-tag-restricted-to-approved-apps","errorCode":null,"errorMessage":"Device tag restricted to approved apps","messagePattern":"Device tag restricted to approved apps","errorType":"exception","errorClass":"SecurityException","httpStatus":null,"severity":"error","filePath":"play-services-location/src/main/java/com/google/android/gms/location/reporting/ReportingState.java","lineNumber":56,"sourceCode":"    public final boolean canAccessSettings;\n    @Field(11)\n    public final boolean hasMigratedToOdlh;\n\n    @Constructor\n    public ReportingState(@Param(2) int reportingEnabled, @Param(3) int historyEnabled, @Param(4) boolean allowed, @Param(5) boolean active, @Param(7) int expectedOptInResult, @Param(9) int expectedOptInResultAssumingLocationEnabled, @Param(8) Integer deviceTag, @Param(10) boolean canAccessSettings, @Param(11) boolean hasMigratedToOdlh) {\n        this.reportingEnabled = reportingEnabled;\n        this.historyEnabled = historyEnabled;\n        this.allowed = allowed;\n        this.active = active;\n        this.expectedOptInResult = expectedOptInResult;\n        this.expectedOptInResultAssumingLocationEnabled = expectedOptInResultAssumingLocationEnabled;\n        this.deviceTag = deviceTag;\n        this.canAccessSettings = canAccessSettings;\n        this.hasMigratedToOdlh = hasMigratedToOdlh;\n    }\n\n    public int getDeviceTag() throws SecurityException {\n        if (this.deviceTag == null) throw new SecurityException(\"Device tag restricted to approved apps\");\n        return deviceTag;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return ToStringHelper.name(\"ReportingState\")\n                .field(\"reportingEnabled\", reportingEnabled)\n                .field(\"historyEnabled\", historyEnabled)\n                .field(\"allowed\", allowed)\n                .field(\"active\", active)\n                .field(\"expectedOptInResult\", expectedOptInResult)\n                .field(\"deviceTag\", deviceTag == null ? \"(hidden-from-unauthorized-caller)\" : deviceTag.intValue())\n                .field(\"expectedOptInResultAssumingLocationEnabled\", expectedOptInResultAssumingLocationEnabled)\n                .field(\"canAccessSettings\", canAccessSettings)\n                .field(\"hasMigratedToOdlh\", hasMigratedToOdlh)\n                .end();\n    }","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-location/src/main/java/com/google/android/gms/location/reporting/ReportingState.java#L38-L74","documentation":"ReportingState.getDeviceTag() returns the device tag only if the field was populated by Play services for an approved app; otherwise it throws SecurityException. Device tags are restricted by Google to apps whitelisted for the device-restricted reporting APIs, so unapproved apps can never read this value.","triggerScenarios":"Calling getDeviceTag() on a ReportingState obtained via ActivityRecognition/reporting APIs when the calling app is not on Google's approved allowlist, leaving the deviceTag field null.","commonSituations":"Third-party apps trying to use device-tag-restricted reporting features; apps testing the reporting API without approval; library code assuming deviceTag is always present.","solutions":["Wrap the call in try-catch for SecurityException and handle the null-field case without the device tag.","Request approval from Google for device-tag-restricted reporting APIs if your app legitimately needs them.","Refactor to avoid depending on the device tag; use other ReportingState fields.","Check canAccessSettings/approval status from ReportingState before accessing the tag."],"exampleFix":"// before\nint tag = reportingState.getDeviceTag();\n// after\nint tag;\ntry {\n    tag = reportingState.getDeviceTag();\n} catch (SecurityException e) {\n    tag = -1; // app not approved for device tag\n}","handlingStrategy":"try-catch","validationCode":"// ReportingState exposes no pre-check for deviceTag; inspect toString()/canAccessSettings\nif (state.toString().contains(\"mDeviceTag=null\")) { /* not approved */ }","typeGuard":null,"tryCatchPattern":"try {\n    int tag = state.getDeviceTag();\n} catch (SecurityException e) {\n    // app not approved; proceed without device tag\n}","preventionTips":["Don't assume deviceTag is always present in ReportingState","Request Google approval before relying on device-tag-restricted APIs","Design features to degrade gracefully when the tag is unavailable"],"tags":["android","security","play-services","permission"],"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"}