SReverseby Simpa Labs

DRM

Passing a licence URL through MediaDrmCallback

A DRM playback failure can come from the licence server, from the callback that builds the request, or from the session that is waiting on it. The URL is the fastest way to separate them.

The callback is the only way out of the DRM session

An Android app that plays protected media creates a MediaDrm session and then asks ExoPlayer, Media3 or its own player to obtain a licence. The player cannot talk to the network on the session's behalf. It supplies an object that implements MediaDrmCallback, and the DRM session calls two methods on it: one for provisioning and one for a key request.

That design places the entire network side of licence acquisition inside the callback. The callback method receives the key request bytes and returns the response bytes. Between those two points it decides which URL to use, which headers to send, and how to treat the response. When licence acquisition fails, the callback is the layer where the network details live.

Provisioning is the first call and runs once per device before any licence exists. A provisioning failure produces a different error and a different cause from a licence failure, and a request log that shows only one of the two requests tells you which stage the app reached.

Where the licence URL comes from

MediaDrmCallbackDefault in the Android media libraries builds the request from a licence URL and an optional set of headers. The URL itself has to come from somewhere, and the source determines how stable it is.

  • A constant in the app. The URL is a string literal in the code or a resource, so it appears in the static analysis and does not change between sessions.
  • A field in the media manifest. Streaming manifests carry a licence acquisition field per content item, so the URL varies by asset and is only visible in the manifest the player fetches.
  • A response from an authorisation call. The app or the player asks its own backend for playback rights and receives the URL along with other session data.
  • A provisioning exchange. The provisioning response can carry the licence endpoint that the device is expected to use.

Record the source rather than the value. A URL copied from one session is not guaranteed to be valid for another, particularly when it carries a short-lived token or a session identifier in the path or query.

Telling the failure stages apart

DRM errors are reported as exceptions whose names describe the session rather than the network, so an HTTP failure and a decryption failure can be reported in similar terms. Three stages produce three distinct records.

  • Provisioning failed. The provisioning request returned an error or never completed, so no licence request was attempted.
  • Licence acquisition failed. A request reached the licence server and the response was rejected or the connection failed, so the session exists but has no keys.
  • Licence acquired but playback failed. The response was accepted and keys were installed, and the failure is in the decrypt or render stage instead.

A request log settles this quickly, because each stage produces a distinguishable HTTP call. If the log shows a provisioning call and then a licence call that returned a non-success status, the cause is in the licence server, the request or the URL. If the log shows no licence call at all, the failure happened before the request was made.

An HTTP status from the licence server is informative on its own. A refusal means the server understood the request and declined it, which usually points at entitlement, at the content identifier in the request, or at a token that has expired. The general pattern is the same one described in ExoPlayer network flow.

Headers and signing on the licence request

The callback adds headers to the licence request, and those headers are where an app puts its authorisation and any device identifiers. A licence request is therefore a signed or authenticated API request in its own right, and it needs the same treatment as any other request when it is reproduced.

Check whether the headers include a value computed over the request body, because the licence request body contains binary key request data and a signature over it will not survive a naive re-send. Check whether a token in the headers is bound to the playback session, because such a token is valid once and expires with the session.

The observable point is the same as in other clients: the callback method itself, immediately before and after the transfer. A breakpoint there captures the URL, the headers and the request bytes as the app built them, along with the response bytes that the session accepted or rejected. Android API reverse engineering covers this kind of authenticated request in general terms, and the session lifecycle around the call is described in MediaDrm session lifecycle.

A reconstruction that must obtain licences outside the app needs the URL source, the header set, the signing rule if one applies, and the provisioning step. Android request signing covers the part of that work which concerns computed headers.

Reviewed 28 September 2026 · SReverse research desk

Start your full APK reconstruction

Send the full APK

Projects start at $120. Choose WhatsApp or email, then attach the APK in the app that opens. We reply within one hour with the next step and send the fixed quote after review.

Want us to contact you?