# 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.