# ACR and telemetry: what changed between webOS 3.5 and webOS 24
A differential reading of two extracted LG root filesystems, seven model years apart.
Companion to `acr-telemetry-report-webos-3.5.md` and `acr-telemetry-report-webos-24.md`, which
hold the full evidence for each side.
## Subjects
| | webOS 3.5 | webOS 24 |
| --- | --- | --- |
| Model | 43UJ634V | 55NANO82T6B.BEUSLJP |
| Model year | 2017 | 2024 |
| Platform | webOS 3.5 | webOS TV 24, platform `10.2.2`, `Rockhopper 10.2.2-5901 (ponytail-paparoa)` |
| Firmware | `06.10.75` | `33.22.86` |
| SoC | — | `K8LPN2`, 1.5 GB DDR |
| Service country | NL | NL |
| SDP region | EIC | EIC |
Same market and same regional data centre on both, so regional configuration differences do not
confound the comparison.
## What this compares
Shipped software: binaries, libraries, service manifests, startup activities, configuration
schemas and application source. Per-unit settings state is out of scope — whether a given
feature was switched on by the owner of either set says nothing about the platform, and the two
units were not in comparable states.
Where a runtime artifact is cited below, it is cited as evidence that a code path exists and
executes, not as a statement about either owner's choices.
Both analyses are static. Neither involved disassembly or traffic capture, so control flow and
enforcement conditions remain inferred from strings, symbol names and the source that ships
uncompiled.
---
## 1. Escalations
### 1.1 Wi-Fi scan results are persisted to disk
Both `acr2` builds enumerate neighbouring access points and pass them to Alphonso. On 3.5 this
is `core::WifiInterface`, calling `luna://com.webos.service.wifi/findnetworks` and parsing
`bssid` and `mac_address` out of the reply. On 24 it is `interface::Wifi` with `OnFindNetworks`,
backed by `ASUtilsReadWifiPropertiesThread` and `UtilsReadWifiProperties.cpp` inside
`libas.so.3.0.93`.
The change is where the result goes. The 24 daemon writes it to a named file:
```
/mnt/lg/cmn_data/acr/data/wifi_network_info
[{"mac_address":"…","signal_strength":"-57"},{"mac_address":"…","signal_strength":"-63"}]
```
`cmn_data` is persistent storage. The scan therefore survives reboot and is readable by any
process with access to that tree, rather than existing only in the daemon's memory for the
duration of a lookup. The 3.5 image has no corresponding path in `acr2`'s string table and no
such file in its state directory.
The scan itself remains server-toggled in both (`Recvd enable_wifi_scan:` in `libas.so`), with no
corresponding control in the TV's settings UI on either platform.
### 1.2 ACR results feed the channel-reporting path
On 3.5, `livetvwatch.json` reporting covers the tuner only. Its body has no field for how the
channel was determined, and `PersonalDataService.qml` restricts the whole feature by country:
```
_getEnableCountry() -> KOR, GBR, ESP, FRA, BRA, RUS, DEU
```
On 24 that function is gone — grepping the equivalent
`com.webos.app.inputcommon/qml/Interfaces/ChannelInfoInterfaces/PersonalDataLogger.qml` for a
country list returns nothing. Gating moved to per-source server flags delivered by `pbs`
(`watchFlag`, `ipWatchFlag`, `stbAcrWatchFlag`, `stbScdWatchFlag`, `stbUeiWatchFlag`), each
independently revocable by the server's reply (`activation_flag`, `ip_activation_flag`,
`stb_acr_activation_flag`).
The body gained a provenance field and a separate STB code path (`sendPersonalLogStb`):
```qml
readonly property int fromWhereAcr: 10
readonly property int fromWhereScd: 11
readonly property int fromWhereUei: 12
```
with `checkSendLogStb` implementing the priority ACR > UEI > SCD. Content recognition identifying
what plays on an attached set-top box, and that result being reported to LG as a viewing record,
has no equivalent in 3.5.
### 1.3 Report timing is randomised
24 delays each channel report by a random interval:
```qml
requestTimer.interval = Math.floor((Math.random() * 10000) + 1) + minTime; // minTime = 10000
```
10 to 20 seconds after the event. 3.5 sent on channel change plus a fixed 3-second call after the
channel list loaded. A fixed offset makes a report trivially correlatable with the user action
that produced it; the jitter removes that property.
### 1.4 Server-facing behavioural profiling appeared
The 3.5 analysis examined two candidates and excluded both. `usr/sbin/prs` (Program
Recommendation Service) scored viewing history locally with no `curl_easy_perform` reference and
a zero-byte database. `usr/bin/webos-statistics-manager` wrote only to the local DB8 kind
`com.webos.statisticsManager.appLaunchHistory:1` with no HTTP client linked.
Neither binary exists in the 24 image. What occupies that role now does have server paths:
| Component | Evidence |
| --- | --- |
| `usr-2/sbin/user-context-manager` | `DBHandler::findHistoryInfoForServer`, distinct from the local `findHistoryInfo`; ranked genre, keyword, intent-type and channel profiles; `displayMonthlyReport` |
| `usr-2/sbin/user-intent-manager` | `QueryProcessor::getRank`, `getHistory`, shared kind with UCM |
| `usr-2/sbin/nudge` | Own kind `com.webos.service.nudge.history:1`; ~15 rule files in `mnt-6/lg/cmn_data/nudge/`; server switch `nudge_log_transfer` |
| `usr-2/sbin/contentminer` | Mode 0700, `ContentMinerLogger`, `Callback_GetHttpHeaderForSvcReq` (SDP-authenticated) |
The nudge rules encode the behaviour they watch for, for example
`"zappingHistoryCount": 8, "zappingHistoryRatio": 20` over a 14-day channel-history window.
### 1.5 Ad surfaces expanded, one of them ACR-driven
3.5 had `admanager` alone, serving placements in LG's own interface (Discovery, Browser, Wedge,
LG Channels pause screen).
24 keeps `admanager` and adds:
- `usr-2/sbin/adoverlay-service` — the same architecture as ACR, with its own Alphonso shim
(`libalphonsoadoverlay.so.1.0.0`), its own copy of the fingerprint database
(`usr-2/share/adoverlay/adoverlay.a.2.1.4.db.zero.mp3`), its own vendor-loader directory
(`/mnt/lg/cmn_data/adoverlay/lib/`), and the check `[ACR] ACR Solution is not Alphonso.`
- `com.webos.app.adhdmi1` through `adhdmi4` — per-HDMI-input overlay containers, mirroring the
`acrhdmi1..4` pattern
- `com.webos.app.videoads` — screensaver video ads against `eic.videoads.lgtvcommon.com`
- `CIFAdService::launchCMPApp` — a consent-management-platform hook
The VAST/VPAID tracking vocabulary (`ClickThrough`, `CompanionClickTracking`, `TrackingEvents`,
impression trackers) is present in `admanager` on both platforms and did not change.
### 1.6 The advertising ID is shared with named third-party apps
`mnt-6/lg/cmn_data/sdp/sdx/detailconfig.json` carries two allowlists of apps permitted to read
the device IFA:
```
AdIdWhiteList: amazon
NewAdIdWhiteList: amazon, com.disney.disneyplus-prod, com.twin.app.gamingportal,
com.wbd.hbomax, youtube.leanback.v4
```
`admanager` on 24 also exposes `getAdid` as a subscribable Luna method, which `acr2` watches in
order to restart itself when the identifier changes (activity named `ccpa changed`). Nothing
equivalent appears in the 3.5 material.
### 1.7 More context accompanies each recognition attempt
3.5's `acr2` subscribed to current channel, channel state, last channel ID, input signal state,
current video, screen status, power state, and DVR/timeshift state.
24's `acr2` retains that set and adds `getCurrentEventList` (EPG programme data),
`getHybridTvState` (HbbTV), `getForegroundAppInfo` and `getForegroundVideoWindow`
(which app is on screen and where the video is placed), `getAllInputStatus`,
`getLatestConnectionInfo` and `getDeviceAuthenticationStatus`.
---
## 2. Reductions
### 2.1 Sumo Logic egress removed
3.5's `rdxd` had a second, non-LG destination. `usr/share/rdxd/conf/cloud.json` held three
hardcoded HTTP collector URLs on `collectors.sumologic.com/receiver/v1/http/`, with headers
`X-Sumo-Category: OS/webOS/{Crash,Analytics,Overview}` and `X-Sumo-Name: %nduid%`.
The 24 image has no `sumologic` string anywhere under `usr-2/` or `etc/`, no `conf/` directory
under `usr-2/share/rdxd/`, and no reference to `com.palm.properties.nduid` in any daemon. Crash
and analytics reports now leave only through `uploadd` to LG's own `rdx_secure` host, per
`etc/uploadd.conf`:
```ini
[server=rdx]
AnalyticsLogURL=log/normal
CrashLogURL=log/crash
```
A third-party log SaaS left the crash and analytics pipeline.
### 2.2 Samba TV dropped as a shipped alternative vendor
3.5 carried `usr/lib/libsambasolution.so.1.0.0`, a complete second ACR implementation with its
own libcurl client, selected by setting `ACRSolution="SAMBATV"` in the downloaded config. 24 ships
Alphonso only; a search for `samba` across the image returns nothing relevant.
This is a narrower reduction than it looks. 24 retains `core::SolutionLoader`, which resolves a
vendor engine at runtime from `/mnt/lg/cmn_data/acr/lib/` (empty in this dump) passing it
`WebOSVersion()` and `FirmwareVersion()`. It also carries a server switch for a different vendor
entirely — `thetake_acr` in `detailconfig.json`, currently `off`, with no corresponding binary in
the image. Vendor substitution moved from a second `.so` visible in the firmware to something
fetched at runtime, which is harder to inspect from an image alone rather than more constrained.
---
## 3. What did not change
### 3.1 The Alphonso SDK is the same generation
| | webOS 3.5 | webOS 24 |
| --- | --- | --- |
| Library | `libas.so.3.0.94` (2.1 MB) | `libas.so.3.0.93` (2.5 MB) |
| Build path | `/mnt/alpha/acr-sdk/sdk-build/git-lg-webos-3.5/acr-sdk/` | `/mnt/alpha/acr-sdk/sdk-build/git-lg-webos-24/acr-sdk/` |
| Hosts | `prov-lg.alphonso.tv`, `eulacheck.alphonso.tv` | identical |
The 2017 set carries the marginally newer SDK build number. The request surface is the same on
both:
```
/audio/fingerprint /user /user/location
/user/lookups /user/timed-lookups /user/appsource
/recommendation /recommendation/info /bl/config
/device/config /device/clock /countryList
/latestVersion /log/tar /sdk_debug/stats
```
with the same parameters, including `alp_uid`, `api_key`, `device_id`, `zipcode`, `ipaddr`,
`app_version_code` and `app_version_name`. Seven model years and two major platform generations
produced no change to the collection interface.
### 3.2 `remotediag` still carries LG-internal addresses
Both images contain `rone-{kic,eic,aic}.lge.com` alongside literal internal endpoints. The 24
binary has everything 3.5 had — `165.244.62.249:6120`, `:6230`, `:6240` and
`10.185.223.172:80` — plus `10.150.25.164:6080`, `10.150.25.244:6080` and `165.244.99.174`.
The service remains capable of control as well as diagnostics.
### 3.3 `cdpbeacon_secure` still has no consumer
The 3.5 report flagged `cdpbeacon`, `cdpsvc`, `recommend`, `homeprv`, `nudge` and `wau` as
endpoint-table entries with no code behind them, expected to become live in later firmware.
Partly borne out: `nudge` and `recommend` now have real consumers, and `wau_secure` was dropped
from the table entirely. But `cdpbeacon.lgtvcommon.com` still appears only in
`server_addr_version.conf` itself, with no caller anywhere in `usr-2/palm` or `usr-2/sbin`, seven
years after it was first declared.
### 3.4 The ACR overlay application pattern
Six hidden `LivePlus`-titled web apps on a dedicated window layer, each loading a
server-supplied URL into an iframe with an empty input region and `KeyMaskNone`, one per HDMI
input plus live TV and external-input variants. Identical on both platforms, down to the
`present_frm.html` contents and the `setVideoPig` / `closedApplication` teardown calls.
---
## 4. Smaller changes
**Device identity.** `nduid` is gone from 24. `sdx` uses `LGUDID`/`UDID` with a
`mnt-6/lg/cmn_data/sdp/sdx/udidflag` marker. For viewing reports, `pbs` derives `user_id`
through `UniqueID::getMacAddress` → `encryptMacAddr` → `convertSHA512`, i.e. a SHA-512 over the
MAC address — stable across a factory reset in a way an `nduid` need not be.
**Consent moved server-side.** 3.5 recorded ten local booleans in `var/luna/preferences/eula`
plus a single `X_INT`/`W` entry in `sdx/eula.json`. 24 keeps a server-synchronised, per-country,
version-stamped `statusList` (`S_VNG`, `S_MKT`, `S_SVC`, `S_TAG`, `S_ADG`) and schedules a
two-year marketing re-consent prompt through ActivityManager
(`mnt-6/lg/cmn_data/sdp/sdx/maketingAllowedDate.json`).
**Capture plumbing.** Audio moved off LG's driver interface layer — 3.5 used
`DILE_AUDIO_PCM_RegSendPCMCallback` / `StartUpload` / `StopUpload` against ALSA device
`dsnoop:0,12` — onto plain ALSA through `capture::AlsaAudioWrapper`. Video capture moved out of
`acr2` (`CAPTURE_AcquireVtResouce`, `CAPTURE_CreateContext`) into the shared library
`libvtcapture.so.1` (`screen-capture-webos` 1.0.0-56), reached through a `VTCaptureWrapper`
class, with a new `DaiFastCapture` path alongside it.
**SDP versioning and hostnames.**
| Service | webOS 3.5 | webOS 24 |
| --- | --- | --- |
| `ibis_secure` | `ibs.lgappstv.com` `ibs/v2.8/` | `ibs.nextlgsdp.com` `ibs/10.1.0/` |
| `ibis_stat_secure` | `ibsstat.lgappstv.com` `ibs/v2.8/` | `ibsstat.nextlgsdp.com` `ibs/10.0.0/` |
| `rdx_secure` | `rdx2.lgtvsdp.com` `/v7.0/` | `rdx2.nextlgsdp.com` `rdx/9.0.0/` |
| `cdpbeacon_secure` | `api/v1/beacon/` | `api/v2/beacon/` |
| `cdp_service_secure` | `api/v1.0/` | `api/v2.0/` |
| `recommend_secure` | `recommend/v1/` | `recommend/nextsdp/10.0.0/` |
The base domain moved from `lgtvsdp.com` / `lgappstv.com` to the region-prefixed
`nextlgsdp.com`. New entries with no 3.5 counterpart: `sdp_logging`, `rdxdev_secure`
(`rdl.lgtvcommon.com`), `nudge_log_secure`, `service_setting_secure`
(`wiseconfig.lgtvcommon.com`), `cpauth_secure`, `wise_resource_secure`, `qcard`, `sdp_nais`.
**Push.** `usr/sbin/pushmanager` (3.5, against `device.lgeapi.com` / `push.lgeapi.com`) is
replaced by `usr-2/sbin/com.webos.service.pushclient`. Not analysed in either report.
**Analytics event catalogue.** 24 emits `NL_*` key-value events through `PmLogCtl logkv`,
collected by `rdxd`; 584 distinct codes appear across the image, with a scheduler
(`usr-2/sbin/service-logger`) running Python collectors from `etc/palm/service-logger/rules/`.
The 3.5 report notes `rdxd`'s `Analytics` class and `ANALYTICS_REPORT_CREATED` marker but does
not enumerate an equivalent catalogue, so this is a difference in what was measured rather than
a confirmed platform change. Worth re-checking the 3.5 image for `NL_` codes before treating it
as one.
---
## 5. Asymmetry in the available evidence
The 3.5 dump contained `/tmp/acr.xml`, the server-supplied ACR policy, readable in full:
`ACR_On`, `send_data`, `capture_method="SOURCE"`, `client_token`, ``,
per-solution `dai` / `overlay` / `lgchannels` flags, and the resolution ceilings.
The 24 dump has no equivalent file. `acr2` still fetches one — the strings `/tmp/acr.xml`,
`/mnt/lg/cmn_data/acr.xml`, `ACR_VERSION_DOWNLOAD`, `requestACRVersion`, `getACRPath` and
`(Sdx) call failed to download acr config : %s` are all present — but the fetched copy lives in
`/tmp` and did not survive extraction.
Consequences for reading the two reports side by side:
- Statements about what the server permits are strong on 3.5 and absent on 24. In particular,
whether video capture is enabled on the newer platform is not established. `acr2` links
`libvtcapture` and carries a `DaiFastCapture` path, but 3.5 also carried complete video capture
code with the config flag set to `false`. Presence of the code proves nothing either way.
- `ACRSolution`, `send_data` and the Alphonso `enable_wifi_scan` flag are all server-set on both
platforms and can change without a firmware update, so neither report's findings on those
points are durable.
Retrieving `/tmp/acr.xml` from a running webOS 24 set would close the largest gap between the two
analyses. Beyond that, the open items are the same on both: no disassembly of `acr2` or
`libas.so`, and no traffic capture to confirm which fields are actually transmitted.