What the Media3 split changes
Media3 ships as several artifacts. The core player and the DRM interfaces live in the ExoPlayer artifact, while manifest support for each streaming format and the optional HTTP clients arrive in separate dependencies. An app that plays DASH protected content therefore pulls in the core player, the DASH module, a data source module and a UI module, and each of those brings its own package prefix under androidx.media3.
For analysis this matters in one practical way: the DRM code is present even when a decompiled listing looks sparse, because the interfaces are small and the implementation is concentrated in a handful of classes. Searching for a licence URL, a scheme UUID or the string constants used in DRM configuration finds the app's wiring faster than reading the player.
How an app supplies DRM configuration
Two styles appear in real applications, and they behave differently at run time.
- A DRM configuration attached to the media item, carrying the scheme UUID, the licence URI and any key set identifier. The player builds a session manager for that item, which is why two titles in one app can use different licence hosts.
- A session manager installed on the player or on the renderers factory, which applies to every item the player loads. This style usually appears when the app has one licence host and one token source.
Media3 also allows a provider that creates a session manager per media item, which combines the two styles: the app keeps one code path but the manager is constructed with values from the item. When you read an APK, expect to see the DRM configuration object used with the media item and a provider or factory object registered on the player.
What the session manager is built from
A default session manager takes a DRM callback and a source of platform DRM instances. The callback is the object that performs network requests, and the platform source is what wraps android.media.MediaDrm. Applications that need custom behaviour replace one or both.
Common customisations and what they mean for reconstruction:
- A replacement callback routes licence traffic through the app's HTTP client, so the request inherits the app's interceptors, certificate handling and logging.
- A platform DRM wrapper sets properties such as the security level before a session opens, which can change whether a licence server accepts the device.
- The multi-session flag controls whether each track gets its own session. With multiple sessions, a trace shows more licence requests and each carries the init data for one track.
- Key request parameters let the app pass values that the CDM includes in the message it builds, which is a common place to find a DRM token that never appears in an HTTP header.
Initial, renewal and release requests
The same session produces several requests over its life. The first is the initial licence request, sent when the session opens. A renewal follows when the licence approaches expiry, and the CDM decides that, not the app. A release request can be sent when the session ends or when the player stops, and it is easy to mistake for a licence failure when you read a capture in order.
An app that pauses playback for a long period may let a licence expire and acquire a new one. A trace of a single playback session can therefore contain requests spread across the whole session, and any client you build needs to handle the same lifecycle rather than performing one call and assuming it stays valid.
Offline playback and stored licences
Media3 supports downloading protected content and keeping a licence on the device. The download path requests an offline licence, which the CDM stores, and the resulting key set identifier is what the player uses later to resume playback without contacting the licence server. That identifier is persisted, typically in preferences or a local database, and it can be restored on a later launch.
This produces a flow that looks nothing like streaming. There may be no licence request at all during the second playback, only a restore that reads the stored key set. If an app supports downloads, look for the identifier and for the code that passes it into the DRM configuration, because that code is the whole authorization path for offline playback.
Errors and what they tell you
Media3 reports DRM problems as playback exceptions that wrap a session error. The distinction worth preserving in your notes is between a session that could not be created, a session that opened but received no keys, and a session that produced keys the decoder refused. The first points at configuration, the second at the licence exchange, and the third at the content or the device rather than at the app's token.
Provisioning failures surface early, before any licence request appears. A device with no CDM certificate cannot produce a usable key request, so a trace that stops at that point is complete rather than truncated. The reverse also holds: a licence POST that reaches the server and returns a body means the app's configuration was correct, and the refusal came from policy or from an expired credential.
Searching a Media3 application
Start from the strings, then move to the classes. Licence hostnames, a scheme UUID, and the names of the DRM interfaces are quick to locate in a decompiled APK. From each hit, read outward to the media item construction and to whatever supplies the token. In an app that uses a custom callback or interceptor, that path ends in the code that signs or authorises every other API call, which is where the reconstructable logic lives.
Related work
Reviewed 28 September 2026 · SReverse research desk