android-reverse-engineering.../plugins/android-reverse-engineering/skills/ad-analysis/references/mediation-patterns.md

7.9 KiB

Mediation Patterns

How ad mediation works in decompiled Android code — identifying the primary mediator, adapter chains, waterfall vs bidding, and configuration extraction.

What is Mediation

Ad mediation allows an app to use multiple ad networks through a single SDK. A mediator (e.g., AdMob, IronSource, AppLovin MAX) orchestrates which ad network serves each impression via:

  • Waterfall: Networks are tried in priority order; first to fill wins
  • Bidding (header bidding): Networks bid simultaneously; highest bid wins
  • Hybrid: Some networks bid, others fill via waterfall

Identifying the Primary Mediator

The mediator is the SDK that controls ad loading. Look for:

Google AdMob Mediation

// AdMob is the mediator when you see mediation adapters:
com.google.ads.mediation.*
// Adapter classes follow the pattern:
com.google.ads.mediation.unity.UnityAdapter
com.google.ads.mediation.ironsource.IronSourceMediationAdapter
com.google.ads.mediation.applovin.AppLovinMediationAdapter
com.google.ads.mediation.facebook.FacebookMediationAdapter
com.google.ads.mediation.vungle.VungleMediationAdapter

Grep:

grep -rn 'com\.google\.ads\.mediation\.' "$SOURCE_DIR"

IronSource / LevelPlay Mediation

// IronSource is the mediator when you see adapter packages:
com.ironsource.adapters.*
// Adapter naming:
com.ironsource.adapters.admob.*
com.ironsource.adapters.unityads.*
com.ironsource.adapters.applovin.*
com.ironsource.adapters.facebook.*
com.ironsource.adapters.vungle.*

Grep:

grep -rn 'com\.ironsource\.adapters\.' "$SOURCE_DIR"

AppLovin MAX Mediation

// MAX is the mediator when you see MAX adapter packages:
com.applovin.mediation.adapters.*
// Adapter classes extend MediationAdapterBase:
com.applovin.mediation.adapters.GoogleMediationAdapter
com.applovin.mediation.adapters.UnityAdsMediationAdapter
com.applovin.mediation.adapters.IronSourceMediationAdapter
com.applovin.mediation.adapters.FacebookMediationAdapter

Grep:

grep -rn 'com\.applovin\.mediation\.adapters\.' "$SOURCE_DIR"

Waterfall vs Bidding

Waterfall indicators

# Priority/floor price configuration
grep -rn 'waterfall\|floorPrice\|ecpm\|eCPM\|setPriority\|adNetworkOrder' "$SOURCE_DIR"

# Manual network ordering
grep -rn 'setNetworkOrder\|setAdapterOrder\|setWaterfallConfiguration' "$SOURCE_DIR"

Bidding indicators

# Real-time bidding signals
grep -rn 'bidding\|headerBidding\|bidToken\|collectSignal\|getBiddingToken' "$SOURCE_DIR"

# Bidding adapter classes (often have "Bidding" in the name)
grep -rn 'BiddingAdapter\|BiddingProvider\|RTBAdapter' "$SOURCE_DIR"

# MAX bidding
grep -rn 'MaxMediatedNetworkInfo\|isBidding\|bidFloor' "$SOURCE_DIR"

Adapter Discovery

List all mediation adapters present

# Find all adapter class files
find "$SOURCE_DIR" -path "*/mediation/adapters/*.java" -o -path "*/adapters/*Adapter*.java" | head -50

# Find adapter registration/initialization
grep -rn 'registerAdapter\|initializeAdapter\|setAdapterState\|MediationAdapter' "$SOURCE_DIR"

Extract adapter configuration

# Network IDs and app keys passed to adapters
grep -rn 'setAppKey\|setAppId\|setGameId\|setSdkKey\|setNetworkKey' "$SOURCE_DIR"

# Ad unit/placement mapping (mediator → network)
grep -rn 'placementMap\|adUnitMap\|networkPlacementId\|customEventExtras' "$SOURCE_DIR"

Common Mediation Setups

Setup 1: AdMob as Mediator

AdMob (primary) → loads via:
  ├── Google Ads (direct)
  ├── UnityAdapter → Unity Ads SDK
  ├── IronSourceMediationAdapter → IronSource SDK
  ├── AppLovinMediationAdapter → AppLovin SDK
  └── FacebookMediationAdapter → Meta AN SDK

Setup 2: IronSource/LevelPlay as Mediator

IronSource (primary) → loads via:
  ├── IronSource Network (direct)
  ├── AdMob adapter → Google Mobile Ads SDK
  ├── Unity adapter → Unity Ads SDK
  ├── AppLovin adapter → AppLovin SDK
  └── Vungle adapter → Vungle SDK

Setup 3: AppLovin MAX as Mediator

AppLovin MAX (primary) → loads via:
  ├── AppLovin Network (direct, always bidding)
  ├── GoogleMediationAdapter → AdMob SDK
  ├── IronSourceMediationAdapter → IronSource SDK
  ├── UnityAdsMediationAdapter → Unity Ads SDK
  └── FacebookMediationAdapter → Meta AN SDK

Active vs Passive SDKs

When mediation is present, most ad SDKs in the APK are passive dependencies — they are only invoked internally by the mediator's adapter classes, never by the app's own code.

The Entry Point Graph

App code (com.example.myapp.*)
    │
    ▼
Mediator SDK (e.g., AdMob)          ← ACTIVE: called by app code
    │
    ├──→ Adapter (com.google.ads.mediation.unity.*)
    │        └──→ Unity Ads SDK     ← PASSIVE: called only by adapter
    │
    ├──→ Adapter (com.google.ads.mediation.ironsource.*)
    │        └──→ IronSource SDK    ← PASSIVE: called only by adapter
    │
    └──→ Adapter (com.google.ads.mediation.applovin.*)
             └──→ AppLovin SDK      ← PASSIVE: called only by adapter

How to Distinguish

An SDK is active if its init/load/show calls appear in app code. An SDK is passive if its code is present only inside library packages.

Key principle: Search for SDK calls only in non-library directories. Known library packages to exclude:

Package prefix SDK
com/google Google/AdMob
com/unity3d Unity Ads
com/ironsource IronSource/LevelPlay
com/applovin AppLovin/MAX
com/facebook Meta Audience Network
com/vungle, io/vungle Vungle/Liftoff
com/inmobi InMobi
com/chartboost Chartboost
com/bytedance, com/pgl Pangle/TikTok
com/mbridge, com/mintegral Mintegral

Grep Examples

# Search for ad SDK calls ONLY in app code (exclude all library packages)
grep -rn --include="*.java" --include="*.kt" \
  --exclude-dir="com/google" --exclude-dir="com/unity3d" \
  --exclude-dir="com/ironsource" --exclude-dir="com/applovin" \
  --exclude-dir="com/facebook" --exclude-dir="com/vungle" \
  --exclude-dir="com/inmobi" --exclude-dir="com/chartboost" \
  --exclude-dir="com/bytedance" --exclude-dir="com/pgl" \
  --exclude-dir="com/mbridge" \
  -E '(MobileAds\.initialize|UnityAds\.initialize|IronSource\.init|AppLovinSdk\.getInstance)' \
  "$SOURCE_DIR"

Interpreting results:

  • If MobileAds.initialize appears in com/example/myapp/AdManager.java → AdMob is active
  • If UnityAds.initialize appears only in com/google/ads/mediation/unity/UnityAdapter.java → Unity Ads is passive (but this file is excluded, so it won't show up)
  • If UnityAds.initialize appears in com/example/myapp/AdsHelper.java → Unity Ads is also active (direct integration alongside mediation)

Architecture Classification

Architecture Meaning Example
Single mediator App calls 1 SDK; all others are passive adapter deps AdMob init + 5 mediated networks
Multiple direct App calls 2+ SDKs directly; no mediation AdMob banners + Unity interstitials
Hybrid App calls a mediator + some SDKs directly AdMob mediation + direct IronSource rewarded

Automated Detection

Use the --entrypoints flag of find-ads.sh:

bash find-ads.sh <source-dir> --entrypoints

This runs the exclusion-based grep automatically and shows only app-initiated SDK calls.

Extracting Mediation Configuration

Look for server-side configuration that controls the mediation waterfall:

# JSON config responses from mediation servers
grep -rn 'mediationConfig\|auctionResponse\|waterfallConfig\|adNetworkConfig' "$SOURCE_DIR"

# Remote config / A/B test for ad setup
grep -rn 'RemoteConfig.*ad\|firebase.*ad_config\|ad_waterfall\|ad_network_ids' "$SOURCE_DIR"