Permissions make it possible for AppLovin to do what the allegation claims

This post is part of AppLovin Nonconsensual Installs. See important disclosures.

Ordinarily, if app A wants to install app B, it must send the user to Google Play—where installation only proceeds if the user taps the prominent green Install button. At Google Play, accidental installs are rare, and nonconsensual installs are effectively unheard of.

If installations occur outside Google Play, the first question is technical feasibility. It is not enough that source code appears to support this behavior (as shown in my execution path analysis); the Android security model must also allow it. A close review of security settings in the relevant manifests shows that such installs are indeed possible—and in fact, the unusual settings documented on this page are difficult to explain any other way.

Save The Girl manifest indicates authorization to invoke AppHub

The Android game “Save The Girl” includes the following entry in its manifest:

<intent>
<action android:name="com.applovin.am.intent.action.APPHUB_SERVICE"/>
</intent>

Ordinarily, apps do not need this line to receive ads from AppLovin.  So why does this game—and dozens of others—request permission to invoke AppHub?  What legitimate purpose does this serve?

AppHub manifest indicates authorization to invoke T-Mobile packages with elevated permissions

The AppHub manifest includes permission to interact with a T-mobile installer helper:

<uses-permission android:name="com.tmobile.dm.cm.permission.UPDATES_INSTALL"/>
<uses-permission android:name="com.tmobile.dm.cm.permission.UPDATES_LOCAL_INSTALL"/>
<uses-permission android:name="com.sprint.permission.INSTALL_UPDATES"/>
<uses-permission android:name="com.sprint.permission.INSTALL_LOCAL_UPDATES"/>
<queries>
<package android:name="com.tmobile.pr.adapt"/>
<package android:name="com.sprint.ce.updater"/>
<package android:name="com.tmobile.dm.cm"/>
</queries>

One plausible explanation is that AppHub uses a T-Mobile install helper to complete out-of-box (OOBE) installations.  But that only raises a further question: Why would third-party games need to connect to the same privileged middleware?

Com.tmobile.dm.cm has elevated permissions including installing other apps

The com.tmobile.dm.cm package has the critical permission necessary to install other apps.

<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
<uses-permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES"/> ...

Reviewing code, I found that this is the package that ultimately installs promoted apps.  The combination of that code (which passes execution to the installer) and this permission (which grants the package the ability to do so) reinforce my conclusion.

Some AppLovin APKs seek permission to install apps themselves, without a manufacturer/carrier install helper

In some cases, AppHub does not rely on a manufacturer or carrier install helper.  Certain AppLovin APKs instead request install permissions directly. For example, the Adapt v3.40.2 manifest includes:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="3400299"
android:versionName="3.40.2"
android:compileSdkVersion="34"
android:compileSdkVersionCodename="14"
package="com.tmobile.pr.adapt"
platformBuildVersionCode="34"
platformBuildVersionName="14">
<uses-sdk
android:minSdkVersion="23"
android:targetSdkVersion="34"/>
<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>...

AppLovin’s public statements are consistent with AppLovin sometimes receiving this permission. From AppLovin’s Array Terms:

To provide the Array Services to you, we may need access to the “INSTALL_PACKAGES” and “QUERY_ALL_PACKAGES” Android device permissions. We receive these permissions through your carrier or mobile phone original equipment manufacturer, and we use them to provide you with the Array Services, including presenting Direct Download screen to you and facilitating the on-device installation of mobile applications at your election (where Array acts as the technical installer, not your carrier).

This paragraph — including phone manufacturer or carrier preinstalling AppLovin code and presetting these permissions — matches what I observed. Of course the “at your election” claim is contrary to my analysis of the execution path, and my tabulation of user complaints, indicating nonconsensual installations.

Labels and strings in AppLovin code

This post is part of AppLovin Nonconsensual Installs. See important disclosures.

Flipping through AppLovin APKs, it is easy to find labels and strings that appear to indicate nonconsensual installations. Examples are below.

These labels must be interpreted with care. Ultimately these are labels, not directly indicating actual application functionality. Anyone could name a function FlyToMoon(), but that doesn’t mean he has a rocket or a launchpad.

Furthermore, there could be proper reasons for certain silent installs. Consider the out-of-box experience, when it is routine for manufacturers and carriers to place apps on a user’s device. Consider installations in which user consent is obtained in some earlier part of the process.

Overall, I consider the execution path a more reliable method of determining what AppLovin’s code does. On the other hand, the execution path is complicated—requiring parsing thousands of lines of code to follow the flow, and requiring substantial technical skills to understand the code. In contrast, reviewing strings can be as easy as Edit-Find and dictionary meaning.

Labels and strings in Java code

AppLovin’s code includes various labels that indicate or reference nonconsensual installations. A representative example: com.applovin.array.apphub.tmobile includes a class called TmobileSilentInstallManager. The literal meaning of a “silent install” is one without user consent.

Elsewhere in AppLovin code, there are hundreds of references to “Install”, “Installer”, “installing”, “startInstall”, and the like, including more precise labels such as “andr_app_installing_start”, “an.ui.ntfn.installing_progress.enabled”, and “package_installing_successfully_finished_notification_id”. AppLovin logging also includes status messages like “Failed to start install”, “Failed to start installing”. These labels and strings leave no doubt that AppLovin can install apps—but they do not prove that installations are silent, automatic, or nonconsensual. Other labels, like “DirectInstallOrDownload”, indicate a nonstandard installation (not via Google Play) and suggest the install has few steps (calling into question what disclosure is provided and what consent obtained), but again are less than complete proof.

Labels in JavaScript code

The AppHub APK embeds a resource file, index-BFfWBgBF.js, which contains labels indicating non-consensual “auto” installations. The file merits close examination (see my execution path analysis), but even its labels reveal its purpose. For example:

e.IsAutoInstallEnabled="ui.dd.mp.installation_countdown"
e.AutoInstallDelayMs="ui.dd.mp.install_countdown_ms"
const wt = {
...
autoInstallDelayMs: 5e3,
isAutoInstallEnabled: !0,
...

shouldStartAutoInstall
SetInstallationOnDismissEnabled
isAutoInstall
AppAutoInstallTimerEnd

Other labels indicate that installation may occur simply when a user closes an ad:

e.IsOneClickInstallOnCloseEnabled
...
const wt = {
...
isOneClickInstallOnCloseEnabled: !0
...
SetInstallationOnDismissEnabled

A JavaScript “Breadcrumb” message logger even records a possible event, “Installation on ‘X’ button click”. Yet clicking an X is ordinarily understood as rejection, not consent. Similarly, an error handler describes “Failed to set installation on dismiss enabled”—implying that, when working correctly, the code can indeed install on dismiss. But what user thinks “dismiss[ing]” an ad is basis for an installation? Code snippets below.

catch(a => {
    pe.reportError(new Error("Failed to set installation on dismiss enabled", {
pe.leaveBreadcrumb({
    message: 'Installation on "X" button click', ...

Taken together, these labels describe scenarios where installations proceed without a user being asked to install or without the user agreeing to install.

Possible settings screen entries consistent with automatic installations

The resource file index-BFfWBgBF.js also includes a potential settings screen with the following labels:

zu = "Enable Direct Download",
Gu = "Download apps with a single click", ...
Ra = { EnableDirectDownload: zu,
EnableDirectDownload_Description: Gu, ...

From the resource file alone, it is unclear whether this screen is ever presented to users, and if so, under what conditions or with what default setting. Yet users consistently report unexpected app installations, suggesting that the option may be enabled by default—or hidden in a screen users do not ordinarily open.

My personal experience reinforces doubt about such a screen being shown to users. In spring 2025, I purchased a new T-Mobile phone directly from the carrier. On first boot, the out-of-box setup prominently displayed AppLovin screens urging me to download apps. At no point did I see any option to “Enable Direct Download” or to “Download apps with a single click.”

User complaints confirm that no such screen is shown. In reviewing complaints, I found no screenshots of such a screen being proactively shown. One user noted:

I found an app called Content Manager on my Samsung S24 that I bought through T-Mobile. There was an option there that says “Allow Install of New Apps” and I turned it off, and the ad installs stopped. (Skybreak, April 6, 2024)

This complaint reinforces the problem: a user would have no reason to hunt through a Content Manager settings screen to disable unwanted installs. Nor does failing to disable a buried option constitute consent for arbitrary app installations.

AppLovin Execution Path

This post is part of AppLovin Nonconsensual Installs. See important disclosures.

A reliable way to understand what software does is to examine its source code and trace the execution path.  This is rarely possible for compiled code, but AppLovin is largely Java, which can be decompiled using tools such as JADX.  I reviewed decompiled source code alongside the full app manifests and relevant resource files embedded within APKs.  Together, these materials reveal both what the apps are permitted to do (via permissions), how execution proceeds from function to function, and, ultimately, what occurs.

Let me remark on three key challenges in interpreting the decompiled code.  First, length.  After decompilation using JADX, the AppHub APK totals a remarkable 626,053 lines of code.  Then there’s more in the AppLovin SDK, in install helpers, in manifests, and in JavaScript.  Of course most of the code is irrelevant to app installs.  In the excerpts linked below, I focus on what I found to be relevant.  But the execution path remains lengthy even after excerpting.

Second, both decompilation and deliberate obfuscation by AppLovin make parts of the code difficult to read.  Decompilation recovers some labels (function names and variable names), but others are lost and must be generated by JADX – yielding labels that are difficult to interpret (such as AbstractC1838d0) and not the labels actually used in AppLovin’s source code.  Meanwhile, AppLovin intentionally obfuscated (minified) its JavaScript—not unexpected, because they have no reason to help anyone read it, but still an impediment to understanding.

Third, Android’s architecture—including coroutine continuation functions for multithreading—adds further complexity.  This code is not the simple a() calls b() calls c() taught in introductory programming classes.

Nonetheless, with knowledge of Java syntax and Android architecture, and with determination and grit, the execution flow is apparent.  I worked on understanding this code on-and-off from February to September 2025, and I now feel I have a good understanding.  My remarks below are my best effort under important constraints, including both the size of the task and AppLovin’s intentional obfuscation.  I cannot guarantee perfection.  See my disclosures.

In the index below, I present code in the sequence in which it operates.  Where a function name is less than self-explanatory, I remark on its purpose.  In the linked pages, I introduce each block of code with a short narrative about key steps, and I use red text to mark the flow from one step to the next.  Occasional comments, marked with the prefix // , are added by me to explain selected areas.

In the AppLovin SDK

trackAndLaunchClick()

startDirectInstallOrDownloadProcess()

showDirectDownloadAppDetailsWithExtra()

AppHub mRemote.transact()

In AppHub wrapper

onTransact()

showDirectDownloadAppDetailsWithExtra() with service method AbstractC1838d0.m3826C(),delegate C2823r(), and Kotlin coroutine continuation with entry point mo410()

BinderC2829u.m4811d() creates intent DirectDownloadActivity

c3429t1.m5750a()

C3394o1 with continuation entry point mo410r()

In DirectDownloadActivity

onCreate()

onAppDetailsCreate()

setupAppDetailsFragment() and coroutine continuation class C3359j1 with continuation entry point mo410r()

DirectDownloadMainFragment C3374l2 and onViewCreated mo1147B() with coroutines C3339g2, C3332f2, and C3325e2, plus coroutine continuation orchestrator M5734P and URL builder m5748L

AbstractC3404p4.mo1147B() with C3334f4 and C3320d4 (WebView loader)

DirectDownloadMainFragment continuation entry point mo410r()

WebView loads JavaScript resources that implement auto-install

C4785e (WebView loader)

Variable wt (default configuration)

Wt() checks IsAutoInstall and installs if set

C() checks isOneClickInstallOnCloseEnabled and installs if set

Wt() checks if AutoInstallDelayMs is set, and if so uses av() to hook a timer’s onExpire event to the install function

c() install function

Ge.installApp() hooks /install-app endpoint

makeNativeXhrRequest()

makeHttpRequest() wraps browser-native XMLHttpRequest

Java URL interceptor prepares to run T-mobile InstallerHelper

DirectDownloadMainFragment C3374l2 creates C3298a3 which creates C5252f (WebView interception manager)

C5252f registers endpoint handler C5461u for /install-app

C5461u activates DirectDownloadPackageManager C2495r1 with coroutine resume function m4446F()

C0033f0 creates C0023a0 (installation executor) and coroutine resume function m431o() and continuation entry point mo410r()

mo410r() runs T-Mobile InstallerHelper startInstall()

In T-Mobile InstallerHelper

m14262a message dispatcher

sendEmptyMesage()

startInstall()

prepareInstall()

performInstallBundle()

m14247a (InstallParams method)

PackageInstaller (Android Package Manager from core Android)

Prior Critiques of AppLovin

This post is part of AppLovin Nonconsensual Installs. See important disclosures.

My work follows six prior critiques in which others questioned AppLovin practices, both as to app installations and beyond.  I organize those critiques here, in chronological order, to assist those who wish to reread them. I emphasize those reports and sections that, like my post today, consider nonconsensual installations.

Culper 1 – pages 7-25 about installs

Fuzzy Panda – Part II discusses Direct Downloads and other methods of gaming installs (citing my work), among other subjects

Culper 2 – broader topics: misrepresentation of Chinese ties, national security concerns

Muddy Waters – focused on tracking and persistent identifiers

Mike Shields – on installs (citing me)

Olivia Solon (Bloomberg) – reporting an SEC probe of AppLovin’s data-collection practices

Compared with prior reports, I provide a more detailed technical analysis. For example Solon’s report of SEC inquiry does not provide any source code, screenshots, packet logs, or other direct evidence of data collection violations. I also provide greater proof relative to prior reports of nonconsensual installations. For example, the prior reports about nonconsensual installs present snippets of code, whereas I trace the full execution chain from ad delivery all the way to installation. Similarly, prior reports offer a few complaints about nonconsensual installations, but I offer hundreds, plus I explore patterns of complaints across devices and situations, and I cross-check complaints against details in decompiled AppLovin code.

AppLovin – My disclosures

This post is part of AppLovin Nonconsensual Installs.

In January 2025, I was engaged by an investment firm that was skeptical of AppLovin.  They asked me to investigate a range of concerns, including installation practices.  That engagement continued until June 2025.  My agreement with that firm disallows me from revealing its name, but allows me to share all information I figured out from public sources.  Since then, I have had no paid relationship with that firm—or any other investment firm—regarding AppLovin.

As part of my research for this post, I spoke with a range of experts concerned about AppLovin’s practices, including security researchers, journalists, industry analysts, attorneys, and competing adtech firms.  No money changed hands in any of these discussions.  As my post indicates, my primary methodology was forensic: I reviewed AppLovin source code and tested the product first-hand, plus examined user complaints.

From my extended analysis, I became convinced that AppLovin engaged in serious misconduct.  The accompanying report details the methods and evidence supporting this conclusion.

Consistent with my practice whenever contractually permitted, I am releasing this report publicly for anyone to use.  To the best of my knowledge, the information herein is accurate and based on sources and methods I consider reliable.  Nonetheless, all content is provided strictly “as is,” without any warranty—express or implied.  I make no representations as to the accuracy, timeliness, completeness, or likely results of using this information.  My research necessarily contains inferences, estimates, and opinions which may prove inaccurate and are subject to risks and uncertainties beyond my control.

This report is not investment advice.  I make no representation or warranty regarding its completeness or the future performance of AppLovin’s securities.  Readers must conduct their own research and due diligence, including consulting with financial advisors, before making investment decisions.

I hold a financial interest in which I profit if AppLovin’s stock price declines.  I opened this financial interest after completing research, based on my serious concern at what I found.  I may change, reduce, or close this position at any time, without notice.  I do not undertake to update this report to reflect changes in my views or positions.  However, if I conclude that I am mistaken about AppLovin’s technology, I will correct the record publicly.

***

Update, October 16, 2025: I no longer have a financial interest relating to AppLovin.

Virgin Atlantic cancelling ticketed and confirmed award travel

I represented Chaim Zeev Rozen in a portion of his formal DOT complaint against Virgin Atlantic.  Mr. Rozen had transferred points from a credit card to Virgin’s frequent flyer program in order to redeem travel for relatives who shared his last name.  Inexplicably, Virgin cancelled the tickets — without telling him or the passengers.

I filed a Reply on Mr. Rozen’s behalf.  I pointed out that, contrary to Virgin’s repeated claim and even its Answer, nothing about his conduct was “fraudulent.” I criticized Virgin’s “fraud detection tools” which supposedly “flagged the booking”. I pointed out that Virgin’s Answer was oddly silent on whether any human even attempted to check whether those tools were correct.  I argued that Virgin did not act reasonably in the penalty it imposed and its handling of Mr. Rozen’s complaint and correspondence alleging error. I identified a DOT regulation and Virgin contract provision that were implicated.

The parties subsequently filed a Notice of Withdrawal of Complaint and Joint Motion to Dismiss, indicating that they reached an amicable resolution of the matter.  A footnote in that filing explains specific improvements Virgin made: new tools to better identify actual fraud, a new process for customer complaints and appeals, and new communications to passengers indicating that bookings have been canceled.  Kudos to Mr. Rozen for his role in bringing about these benefits for the traveling public.

Google Discovery Violations in In re Google Digital Advertising Antitrust Litigation

This post is part of Revisiting Litigation Alleging Google Discovery Violations.

In re: Google Digital Advertising Antitrust Litigation1:21-md-03010-PKC. (S.D.NY.)

MDL docket originated August 12, 2021.  First filing as to spoliation May 30, 2025.

May 30, 2025 letter presents MDL Plaintiffs’ request to file motions seeking an adverse inference against Google based on its spoliation — grounded in its scheme to encourage employees to use Google Chat set to automatically delete messages for employees subject to litigation hold; its failure to ensure that employees complied with litigation holds; and its policy to mislabel sensitive information as “privileged and confidential” to attempt to avoid discovery.

Explains the evidence of Google’s intent to spoliate evidence, including employees discussing what information they should discuss where and how.

Summarizes critical remarks from other courts that examined Google’s spoliation.  Donato: “a permissive adverse inference instruction is a reasonable and proportionate remedy to Google’s intentional failure to preserve relevant evidence.”  Mehta: “Google’s failure to preserve chat messages might” “warrant” sanctions. Brinkema: “systematic disregard of the evidentiary rules regarding spoliation of evidence … may well be sanctionable.”

Criticizes’s Google’s “systematic abuse of privilege” including by CEO Sundar Pichai personally, noting his admission that he “marked e-mails privileged, not because [he was] seeking legal advice, but just to indicate that they were confidential.”  Notes criticism from other courts: Donato: “frankly astonishing abuse of the attorney-client privilege designation to suppress discovery.”  Mehta: “the court is taken aback by the lengths to which Google goes to avoid creating a paper trail for regulators and litigants.”  Brinkema: “misuse of the attorney-client privilege may well be sanctionable.”  Notes that other courts only withheld an adverse instruction because it would have been superfluous given the liability findings already made.

Public comment on passenger complaint about airline overcharge

Aviation enthusiast Mike Borsetti last month alerted the US Department of Transportation to Qatar Airways adding bogus fees contrary to prior representations: Their online check-in allowed him to select a seat free of charge, but at the airport, both check-in staff and a manager said he’d have to pay to keep that seat.  In response, Qatar tried to trivialize Borsetti’s problem — as if this overcharge doesn’t matter or isn’t important enough for DOT to investigate.  In a public comment filed today, I explained why Borsetti is absolutely right:

First, having already complained to both line staff and a manager at the airport, Borsetti had put Qatar amply on notice of the dispute.  Qatar says he should have complained again, after travel, so they could refund him then.  But two unsuccessful discussions with airline staff is more than enough to justify Borsetti’s decision to bring this matter to a regulator.

Second, by all indications the problem stretches well beyond Borsetti alone, and is bigger than Qatar admits.  Online comments already revealed four other customers with substantially the same problem — online check-in seating dishonored unless customers pay more at the airport.  Of customers affected, only a tiny fraction would both realize they were overcharged and then happen to see the one blog discussing Borsetti’s complaint.  So the problem must be substantial.  And that’s as you’d expect: If there’s a defect in Qatar’s software or process, such as airport systems mistakenly saying a seat fee is due even though online check-in already authorized a seat without charge, that problem would occur for a broad swath of passengers since software ordinarily operates predictably and consistently.

On some level Borsetti’s complaint is unusually simple.  He was overcharged, he wants a refund, and he wants Qatar Airways to stop charging passengers for seats it had said would be free.  Will DOT act to make sure all the other affected passengers — who didn’t realize they were overcharged, or didn’t take the time to complain — are also fully refunded?  And will DOT act to make sure that Qatar Airways finally fixes its systems so this problem doesn’t recur?

Turkish Airlines Mishandled Baggage Reimbursements

Congratulations to Mirel Baumgarten, who in 2020 used my formal DOT complaint template to report Turkish Airlines delivering bags 31 hours late and arbitrarily withholding compensation in violation of US law and international treaty.  DOT today cited Mirel in a Consent Order with Turkish, which had to admit its wrongful acts and pay a total of $1.3m (both for delaying refunds after COVID-19 schedule changes and cancellations, and for arbitrarily limiting mishandled bag reimbursements).

DOT summarizes the violation: Turkish Airlines “arbitrarily limited reimbursement for delayed or lost baggage to a maximum amount of $50 USD payment per day for a maximum of six days regardless of the content consumers submitted in their claims.” But, DOT explains, under the Montreal Convention, an airline may not limit its liability for expenses related to delayed baggage to any amount lower than 1,288 SDRs (currently about $1,670).  See Consent Order page 5.

If you enjoy this sort of thing, Mirel’s complaint shows the kind of nonsense airlines all too often inflict on passengers.  Mirel reported bags delivered 31 hours late (complaint page 12) and provides proof with timestamps, yet Turkish oddly categorized the baggage delay as less than 24 hours (not that that would eliminate or even reduce reimbursement under governing treaty and law).  Mirel was traveling for a wedding, had to buy expensive replacement clothes to attend, and had receipts documenting the expenditure.   (See complaint page 11.) Turkish refused to consider Mirel’s evidence, saying the only relevant factor was “the framework of the rules” which purportedly say the Turkish rep “cannot re-evaluate your case” (page 10).  When Mirel cited the specific treaty that required reimbursement of all reasonable expenses subject to the treaty’s cap, disallowing the limitation Turkish proposed, the Turkish rep remarked that no further discussion was possible, “we do not have phone service”, and the specified amount was “our final offer.”  Most consumers would give up.  Kudos to Mirel for sticking with it, telling the DOT, and thereby causing DOT to include this matter in its broader investigation of Turkish.

The DOT’s $1.3m settlement with Turkish is substantial, but that entire amount goes to the US Treasury.  Not a penny flows to the passengers who received arbitrarily reduced reimbursements from Turkish.  Both DOT and Turkish know the names and contact information of affected passengers.  I’d like to see Turkish affirmatively provide every affected passenger with the full amount shown in receipts previously submitted, plus interest.

Other affected Turkish customers should be emboldened by this consent order to demand their full documented loss, no matter any prior protestation by Turkish that its policies called for paying less. I don’t know if Turkish customer service representatives are trained to honor and pay those claims. If not, Turkish customers could contact the attorneys who represented Turkish in this matter, David Endersbee and Barbara Marrin of KMA Zuckert, who should be in a position to press Turkish staff to pay claims consistent with the consent order.