Secure developer options

Per the Android Compatibility Definition Document, OEMs must provide a way to enable app development. However, providing mobile-like developer options within cars leaves those cars vulnerable to attack. Access to developer options can now be gated by an OEM using an authenticated cryptographic token mechanism. Specifically, an OEM can:

  • Specify default restrictions before the first boot.
  • Securely authorize developers, with crypto tokens if preferred.
  • Apply restriction changes once a developer is both authenticated and authorized.

This page describes a reference implementation consisting of a debugging restriction controller app and a remote token issuer endpoint.

Terminology

In addition to Terminology, these terms are used on this page:

  • JSON Web Signature (JWS), defined in RFC 7515
  • National Institute of Standards and Technology (NIST)

Design

OEMs can authorize developers with JSON Web Signature (JWS) tokens (RFC7515). In the reference implementation, access tokens are issued by OEMs and consumed by the restriction controller app. Access tokens are designed to resist replay attacks and forged tokens.

Figure 1. Design

Integration and configuration

OEMs must specify default restrictions on the first boot. OEMs do this with several static resource overlays to override the defaults in the AOSP framework.

The default restrictions for the headless system user can be configured with the config_defaultFirstUserRestrictions string in frameworks/base/core/res/res/values/config.xml, for example:

<!-- User restrictions set when the first user is created.
         Note: Also update appropriate overlay files. -->
    <string-array translatable="false" name="config_defaultFirstUserRestrictions">
        <item>no_debugging_features</item>
        <item>no_install_unknown_sources</item>
        <item>no_install_unknown_sources_globally</item>
    </string-array>

The default restrictions for drivers, passengers, and guests can be configured in frameworks/base/core/res/res/xml/config_user_types.xml. An OEM can overlay these strings to set the default restrictions on each type of user respectively, for example:

<user-types>
    <full-type name="android.os.usertype.full.SECONDARY" >
        <default-restrictions
            no_debugging_features="true"
            no_install_unknown_sources="true"/>
    </full-type>
    <full-type name="android.os.usertype.full.GUEST" >
        <default-restrictions
            no_debugging_features="true"
            no_install_unknown_sources="true"/>
    </full-type>
</user-types>

Build number preference controller

In AAOS, user interaction with the Build Number preference row in Settings is handled by BuildNumberPreferenceController.java located in packages/apps/Car/Settings/src/com/android/car/settings/system/BuildNumberPreferenceController.java.

When the no_debugging_features (UserManager.DISALLOW_DEBUGGING_FEATURES) user restriction is set, BuildNumberPreferenceController suppresses the developer countdown on production (user) builds when tapped:

@Override
protected boolean handlePreferenceClicked(Preference preference) {
    if (DevelopmentSettingsUtil.isDevelopmentSettingsEnabled(getContext())) {
        return true;
    }

    // Enforce restriction on production (user) builds
    if (Build.IS_USER && mUserManager.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES)) {
        showToast(R.string.dev_access_blocked_toast);
        return true;
    }

    mDevHitCountdown--;
    if (mDevHitCountdown == 0) {
        DevelopmentSettingsUtil.setDevelopmentSettingsEnabled(getContext(), true);
        showToast(R.string.show_dev_on);
    }
    return true;
}

Using Build.IS_USER ensures that production builds strictly enforce the security lockdown, while internal engineering teams on userdebug builds can still access developer options using the 7-tap gesture for testing without manual command-line interface (CLI) overrides.

Debugging Restriction Controller

A reference implementation of the Debugging Restriction Controller (DRC) is provided in AOSP at packages/apps/Car/DebuggingRestrictionController.

The DRC lets OEMs dynamically and temporarily lift the no_debugging_features restriction on production vehicles for authorized service technicians and developers. Instead of leaving debugging tools permanently open or requiring firmware re-flashes, the in-vehicle DRC app prompts the user to authenticate with the OEM backend and submit a cryptographically signed access token to enable adb and Developer Options for a finite diagnostic session.

The DRC reference implementation consists of two core components:

  • In-vehicle DRC client app (app/): A privileged system app (holding the MANAGE_USERS permission) on the head unit that authenticates developers, validates the X.509 certificate signature, hostname, nonce, and expiration of incoming JWS tokens, and dynamically toggles the no_debugging_features restriction using UserManager.
  • Cloud Token Issuer (server/): A backend web service (deployable as Firebase Cloud Functions) that authenticates developer credentials and issues cryptographically signed RS256 JWS access tokens with a finite expiration window.

For complete setup instructions, certificate generation tooling, and deployment steps, see the Debugging Restriction Controller integration guide.

Testing

Google recommends that OEMs start with the reference implementation and build out from there.

  1. After configuring the restrictions in the overlay files, compile AAOS and validate the defined flows. Use the reference app and local JWS-enabled service to verify your access settings.
  2. Optional: Configure the system to use your JWS-enabled cloud service. Verify you're observing the expected flow on your backend service.