microg/GmsCore · error · SecurityException

Device tag restricted to approved apps

Error message

Device tag restricted to approved apps

What it means

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.

Source

Thrown at play-services-location/src/main/java/com/google/android/gms/location/reporting/ReportingState.java:56

    public final boolean canAccessSettings;
    @Field(11)
    public final boolean hasMigratedToOdlh;

    @Constructor
    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) {
        this.reportingEnabled = reportingEnabled;
        this.historyEnabled = historyEnabled;
        this.allowed = allowed;
        this.active = active;
        this.expectedOptInResult = expectedOptInResult;
        this.expectedOptInResultAssumingLocationEnabled = expectedOptInResultAssumingLocationEnabled;
        this.deviceTag = deviceTag;
        this.canAccessSettings = canAccessSettings;
        this.hasMigratedToOdlh = hasMigratedToOdlh;
    }

    public int getDeviceTag() throws SecurityException {
        if (this.deviceTag == null) throw new SecurityException("Device tag restricted to approved apps");
        return deviceTag;
    }

    @NonNull
    @Override
    public String toString() {
        return ToStringHelper.name("ReportingState")
                .field("reportingEnabled", reportingEnabled)
                .field("historyEnabled", historyEnabled)
                .field("allowed", allowed)
                .field("active", active)
                .field("expectedOptInResult", expectedOptInResult)
                .field("deviceTag", deviceTag == null ? "(hidden-from-unauthorized-caller)" : deviceTag.intValue())
                .field("expectedOptInResultAssumingLocationEnabled", expectedOptInResultAssumingLocationEnabled)
                .field("canAccessSettings", canAccessSettings)
                .field("hasMigratedToOdlh", hasMigratedToOdlh)
                .end();
    }

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Wrap the call in try-catch for SecurityException and handle the null-field case without the device tag.
  2. Request approval from Google for device-tag-restricted reporting APIs if your app legitimately needs them.
  3. Refactor to avoid depending on the device tag; use other ReportingState fields.
  4. Check canAccessSettings/approval status from ReportingState before accessing the tag.

Example fix

// before
int tag = reportingState.getDeviceTag();
// after
int tag;
try {
    tag = reportingState.getDeviceTag();
} catch (SecurityException e) {
    tag = -1; // app not approved for device tag
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ReportingState exposes no pre-check for deviceTag; inspect toString()/canAccessSettings
if (state.toString().contains("mDeviceTag=null")) { /* not approved */ }

Try / catch

try {
    int tag = state.getDeviceTag();
} catch (SecurityException e) {
    // app not approved; proceed without device tag
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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


AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06). Data as JSON: /api/errors/b45f73d9143bbbc2. Report an issue: GitHub.