[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-105298":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":14,"stars7d":14,"stars30d":14,"stars90d":15,"forks30d":15,"starsTrendScore":16,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":19,"hasPages":19,"topics":21,"createdAt":10,"pushedAt":10,"updatedAt":27,"readmeContent":28,"aiSummary":10,"trendingCount":15,"starSnapshotCount":15,"syncStatus":14,"lastSyncTime":29,"discoverSource":30},105298,"portal-root-kiosk-satellite","jxlarrea\u002Fportal-root-kiosk-satellite","jxlarrea","Root and provisioning for Meta Portal devices for optimal use with Kiosk Satellite.","https:\u002F\u002Fkiosksatellite.com",null,"C",57,8,2,0,6,44.06,"Apache License 2.0",false,"main",[22,23,24,25,26],"facebook-portal","kiosk-satellite","meta-portal","meta-portal-go","root","2026-11-01 00:13:51","\u003Ch1 align=\"center\">\n    \u003Cimg alt=\"Meta Portal Root and Provisioning for Kiosk Satellite\" src=\"assets\u002Fbanners\u002Fbanner3.svg\" width=\"100%\" \u002F>\n     \u003Cp>\u003C\u002Fp>\n     \u003Cp>Meta Portal Root and Provisioning for Kiosk Satellite\u003C\u002Fp>\n     \u003Cp align=\"center\">\n    \u003Ca href=\"https:\u002F\u002Fkiosksatellite.com\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fworks_with-kiosk_satellite-blue?style=for-the-badge&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA5MjQuNDQgOTU5LjU1Ij48cGF0aCBmaWxsPSIjZmZmIiBzdHJva2U9IiM1ZGEzYTYiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iNTIuMTUiIGQ9Ik0zOTAuMTYsNTAuNzVjNDIuNDEtMzIuODksMTAxLjcxLTMyLjg5LDE0NC4xMiwwbDMxMi44OSwyMjQuNzFjMzEuOTQsMjEuODUsNTEuMDksNTguMDEsNTEuMiw5Ni43MXY0NDMuNzNjMCw2NC45My01Mi42NCwxMTcuNTctMTE3LjU3LDExNy41N0gxNDMuNjRjLTY0LjkzLDAtMTE3LjU3LTUyLjY0LTExNy41Ny0xMTcuNTd2LTQ0My43M2MuMTEtMzguNywxOS4yNi03NC44Nyw1MS4yLTk2LjcxTDM5MC4xNiw1MC43NVoiLz48cGF0aCBmaWxsPSIjMThiY2YyIiBkPSJNMjQyLjI1LDUxMS41NWMwLTIyLjUyLDE4LjI1LTQwLjc3LDQwLjc3LTQwLjc3czQwLjc3LDE4LjI1LDQwLjc3LDQwLjc3djE3MC42N2MwLDIyLjUyLTE4LjI1LDQwLjc3LTQwLjc3LDQwLjc3cy00MC43Ny0xOC4yNS00MC43Ny00MC43N3YtMTcwLjY3aDBaIi8%2BPHBhdGggZmlsbD0iI2YyYjcwNSIgZD0iTTM2MS43Miw1MzMuMzVjLjAyLTIyLjUyLDE4LjI4LTQwLjc2LDQwLjgtNDAuNzQsMjIuNS4wMiw0MC43MywxOC4yNSw0MC43NCw0MC43NHYxMjcuMDVjLS4wMiwyMi41Mi0xOC4yOCw0MC43Ni00MC44LDQwLjc0LTIyLjUtLjAxLTQwLjczLTE4LjI1LTQwLjc0LTQwLjc0di0xMjcuMDVaIi8%2BPHBhdGggZmlsbD0iIzNmYmY1ZiIgZD0iTTQ4MS4xOSw0MzUuNjljLjAyLTIyLjUyLDE4LjI4LTQwLjc2LDQwLjgtNDAuNzQsMjIuNS4wMiw0MC43MywxOC4yNSw0MC43NCw0MC43NHYzMjIuMzdjLS4wMiwyMi41Mi0xOC4yOCw0MC43Ni00MC44LDQwLjc0LTIyLjUtLjAxLTQwLjczLTE4LjI1LTQwLjc0LTQwLjc0di0zMjIuMzdaIi8%2BPHBhdGggZmlsbD0iI2U4NjA0YyIgZD0iTTYwMC42NSw1MzAuNTFjLjAyLTIyLjUyLDE4LjI4LTQwLjc2LDQwLjgtNDAuNzQsMjIuNS4wMiw0MC43MywxOC4yNSw0MC43NCw0MC43NHYxMzIuNzRjLS4wMiwyMi41Mi0xOC4yOCw0MC43Ni00MC44LDQwLjc0LTIyLjUtLjAxLTQwLjczLTE4LjI1LTQwLjc0LTQwLjc0di0xMzIuNzRaIi8%2BPC9zdmc%2B&labelColor=444444&color=488284\" alt=\"Made for Kiosk Satellite\" \u002F>\u003C\u002Fa>\n    \u003Ca href=\"https:\u002F\u002Fbuymeacoffee.com\u002Fjxlarrea\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FBuy%20Me%20A%20Coffee-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black\" alt=\"Buy Me A Coffee\">\u003C\u002Fa>\n    \u003C\u002Fp>\n\u003C\u002Fh1>\n\n\u003Cp align=\"center\">\nProvision Meta Portal devices for the best possible\nexperience with \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fjxlarrea\u002Fkiosk-satellite\">Kiosk Satellite\u003C\u002Fa> using a root exploit.\nAll changes are persistent and survive reboots.\n\u003C\u002Fp>\n\n## Overview\n\nThe provisioner checks that the connected Portal has an exact supported model\nand firmware build, briefly uses a root exploit during a controlled reboot,\napplies the features you select, then verifies them across two normal boots.\nPersistent features use focused configuration changes or small boot helpers.\n\n> [!NOTE]\n> This is not a persistent root exploit. It is a timed, surgical way to change otherwise inaccessible system settings and make the most of a Portal with Kiosk Satellite. All features applied by the provisioner are persistent and survive reboots.\n\n> [!WARNING]\n> I have tried to make the provisioner as safe and guarded as possible, but\n> low-level system changes always carry a chance that something could go\n> wrong. Back up anything important and proceed only if you accept that risk.\n> You use this tool at your own risk.\n\n## What the provisioning does\n\n| Feature | What it does and why it helps |\n| --- | --- |\n| [Temporary root provisioning](#how-the-root-exploit-works) | Opens a short privileged window for selected changes, then returns the Portal to normal enforcing mode. |\n| [Persistent wireless ADB](#enable-only-persistent-wireless-adb) | Keeps ADB available on port 5555 after setup, so future reboots no longer require USB activation. |\n| [Non-expiring ADB authorization](#disable-adb-authorization-timeout) | Keeps computers you already approved authorized instead of forgetting their ADB keys after Android's timeout. |\n| [Complete kiosk profile](#run-the-provisioner) | Applies the recommended Kiosk Satellite setup with one command. |\n| [Kiosk Satellite installation](#install-kiosk-satellite) | Downloads, verifies and installs the latest compatible Kiosk Satellite release when the app is missing. |\n| [Hardware audio processing control](#disable-hardware-echo-cancellation-and-noise-suppression) | Stops the Portal from suppressing microphone audio while its speaker is playing audio or music. |\n| [Kiosk Satellite permissions](#grant-kiosk-satellite-permissions) | Enables the microphone, camera, location, storage, presence sensor, overlays, system settings, usage access and reliable background operation. |\n| [Kiosk Satellite Device Owner](#make-kiosk-satellite-the-device-owner) | Gives Kiosk Satellite Android's strongest kiosk-management role. |\n| [Persistent Kiosk Satellite home](#use-kiosk-satellite-as-the-home-screen) | Starts Kiosk Satellite at boot and keeps obsolete Meta screens out of the way. |\n| [Firmware-update blocking](#disable-automatic-meta-firmware-updates) | Prevents an unexpected Meta update from breaking a known working setup. |\n| [Meta remote-wipe blocking](#block-metas-known-remote-wipe-receivers) | Disables Meta's known remote factory-reset entry points while retaining local recovery options. |\n| [Meta app debloat](#disable-unused-meta-applications) | Reduces background work from unused Meta apps, cloud clients and diagnostics. |\n| [Meta-account removal](#remove-local-meta-accounts) | Removes obsolete local account data while retaining services needed by the camera and Portal. |\n| [Presence optimization](#reduce-aiservice-cpu-use-while-preserving-presence-detection) | Lowers AIService CPU use while preserving full-view, LED-free person detection. |\n| [Presence frame-rate cap](#optional-presence-analysis-frame-rate-cap) | Further reduces analysis work without limiting Kiosk Satellite's RTSP frame rate. |\n| [Filtering Private DNS](#configure-dns) | Sends DNS to a chosen DNS-over-TLS resolver for network-level filtering. |\n| [Network-provided DNS](#configure-dns) | Uses the DNS server supplied by the local network, including private LAN hostnames. |\n| [Third-party app updates](#allow-kiosk-satellite-and-third-party-app-updates) | Lets correctly signed Kiosk Satellite and other non-Meta APKs update normally. |\n| [Runtime system theme control](#control-the-runtime-system-theme) | Switches locked Android 10 Portals between light and dark mode through a constrained UID-1000 worker. |\n| [Automatic Shizuku startup](#install-shizuku-with-automatic-startup) | Starts Shizuku locally after every boot for apps that need ADB-shell privileges. |\n| [Read-only status](#status-report) | Reports the device, provisioning and runtime state without exploiting or rebooting. |\n| [Dry-run planning](#dry-run-planning) | Shows required tools, actions and reboots before changing the Portal. |\n| [Private backup bundles](#backup-bundles) | Saves diagnostics and reversible settings in a private, checksummed archive. |\n| [Interrupted-run recovery](#interrupted-run-recovery) | Safely resumes a validated provisioning run after a host or power interruption. |\n| [Exact-build safeguards](#supported-models) | Refuses kernel changes unless the model and full firmware fingerprint match. |\n| [Automatic retry and verification](#running-and-troubleshooting) | Retries race-sensitive attempts and accepts changes only after two verified boots. |\n\n## Requirements\n\n### Host computer\n\n- Linux x86_64 with Git, GNU Make, Python 3.9 or newer and Android Debug Bridge (`adb`)\n- Android NDK r28.2 (`28.2.13676358`)\n- A JDK plus Android SDK Platform 36 and Build Tools containing `aapt`, `zipalign`, `apksigner` and `d8`\n- A USB data cable for initial stock-device setup\n- Internet access when Kiosk Satellite or the pinned Shizuku APK must be downloaded\n\nThe provisioner uses only the Python standard library.\n\n### Portal\n\n- An exact model and firmware build listed under [Supported models](#supported-models)\n- The initial on-screen setup (OOBE) completed so the Debug menu is available\n- ADB enabled in the Portal's Debug menu and the host authorized over USB\n- Wireless ADB enabled for the current boot with `adb -d tcpip 5555`\n- Stable network, a stable IP address and external power for several reboots\n- The physical camera cover open and camera\u002Fmicrophone privacy control off for presence features and the `kiosk` profile\n\nPresence verification checks the live camera pipeline automatically. Nobody\nneeds to remain in view during the reboot sequence.\n\n## Supported models\n\n| Model | Codename | Android | Supported firmware fingerprint | Kernel | Status |\n| --- | --- | --- | --- | --- | --- |\n| Meta Portal Go | `terry` | 10 | `Facebook\u002Fterry_prod\u002Fterry:10\u002FQKQ1.210213.001\u002F5051355900018050:user\u002Fprod-keys` | `4.9.227-perf+` | Tested |\n| Meta Portal 10-inch (1st generation) | `aloha` | 9 | `Facebook\u002Faloha_prod\u002Faloha:9\u002FPKQ1.191202.001\u002F1041515800015050:user\u002Fprod-keys` | `4.4.153+` | Tested |\n| Meta Portal+ (1st generation) | `aloha` | 9 | `Facebook\u002Faloha_prod\u002Faloha:9\u002FPKQ1.191202.001\u002F1041515800015050:user\u002Fprod-keys` | `4.4.153+` | Tested |\n| Meta Portal+ (2nd generation) | `cipher` | 10 | `Facebook\u002Fcipher_prod\u002Fcipher:10\u002FQKQ1.210213.001\u002F4051355900018050:user\u002Fprod-keys` | `4.9.227-perf+` | Tested |\n| Meta Portal 10-inch (2nd generation) | `omni` | 10 | `Facebook\u002Fomni_prod\u002Fomni:10\u002FQKQ1.210213.001\u002F3051355900018050:user\u002Fprod-keys` | `4.9.227-perf+` | Tested |\n| Meta Portal Mini | `omni` | 10 | `Facebook\u002Fomni_prod\u002Fomni:10\u002FQKQ1.210213.001\u002F3051355900018050:user\u002Fprod-keys` | `4.9.227-perf+` | Tested |\n| Meta Portal TV | `ripley` | 9 | `Facebook\u002Fripley_prod\u002Fripley:9\u002FPKQ1.191202.001\u002F2041515800015050:user\u002Fprod-keys` | `4.4.153+` | Tested |\n\nThank you to [@protocol113](https:\u002F\u002Fgithub.com\u002Fprotocol113) for providing\nPortal TV access and sharing the exploit timing observations that helped\nvalidate `ripley` support.\n\nSupport is exact-build specific. Other models and firmware versions\nneed their own verified target before the provisioner will accept them.\nThe `aloha` software family is shared by more than one first-generation form\nfactor. The original 10-inch Portal and 15.6-inch Portal+ share their firmware\nand kernel port, but the provisioner keeps separate exact product-model guards\nfor `Portal` and `Portal+`.\n\nOther firmware builds still need their own verified target. To request support,\nopen an issue with the retail model and this output. Do not publish an ADB\naddress, pairing code or account information.\n\n```sh\nadb shell getprop ro.product.model\nadb shell getprop ro.product.device\nadb shell getprop ro.build.fingerprint\nadb shell uname -a\n```\n\n## Step-by-step installation\n\n> [!WARNING]\n> I have tried to make the provisioner as safe and guarded as possible, but\n> low-level system changes always carry a chance that something could go\n> wrong. Back up anything important and proceed only if you accept that risk.\n> You use this tool at your own risk.\n\n### 1. Install and configure the host tools\n\nInstall the tools listed under [Requirements](#requirements), then clone the\nrepository. The provisioner automatically finds an SDK installed at\n`$HOME\u002FAndroid\u002FSdk` or `$HOME\u002Fandroid-sdk`.\n\n```sh\ngit clone https:\u002F\u002Fgithub.com\u002Fjxlarrea\u002Fportal-root-kiosk-satellite.git\ncd portal-root-kiosk-satellite\n```\n\nIf your SDK is somewhere else, set these paths in the terminal where you run\nthe provisioner:\n\n```sh\nexport ANDROID_SDK_ROOT=\"$HOME\u002FAndroid\u002FSdk\"\nexport NDK=\"$ANDROID_SDK_ROOT\u002Fndk\u002F28.2.13676358\"\nexport ANDROID_JAR=\"$ANDROID_SDK_ROOT\u002Fplatforms\u002Fandroid-36\u002Fandroid.jar\"\nexport BUILD_TOOLS=\"$ANDROID_SDK_ROOT\u002Fbuild-tools\u002F37.0.0\"\nexport D8=\"$BUILD_TOOLS\u002Fd8\"\n```\n\n### 2. Prepare the Portal\n\nComplete the Portal's initial on-screen setup before continuing. The Debug\nmenu and its ADB control are unavailable until the out-of-box experience\n(OOBE) has finished.\n\nOpen the Portal's physical camera cover and turn off its camera\u002Fmicrophone\nprivacy control. The recommended profile installs\n[Kiosk Satellite](https:\u002F\u002Fgithub.com\u002Fjxlarrea\u002Fkiosk-satellite) from its latest\nGitHub release when the app is missing, opens it once and activates its\ndevice-admin receiver. An existing installation and its data are retained.\n\n\u003Ca id=\"connect-to-the-portal\">\u003C\u002Fa>\n### 3. Connect to the Portal\n\nStock firmware disables ADB after every reboot. Open the Portal's Debug menu,\nenable ADB, connect the USB data cable, authorize the host and run:\n\n```sh\nadb -d get-state\nadb -d tcpip 5555\n\nexport PORTAL_IP=192.168.1.100  # replace with the Portal's address\nadb connect \"$PORTAL_IP:5555\"\nadb -s \"$PORTAL_IP:5555\" get-state\n```\n\nBoth state checks must print `device`. Keep USB connected during the first\nprovisioning run.\n\nThe provisioner begins from a clean reboot. On an unprovisioned Portal, enable\nADB again in the Debug menu and rerun `adb -d tcpip 5555` after every reboot\nuntil the provisioner prints `WIRELESS_ADB_OK`. Keep a second terminal ready\nfor this step. After the first successful exploit, wireless ADB survives normal\nreboots and USB is no longer needed.\n\n### 4. Confirm compatibility\n\n```sh\nadb -s \"$PORTAL_IP:5555\" shell getprop ro.product.device\nadb -s \"$PORTAL_IP:5555\" shell getprop ro.build.fingerprint\n```\n\nBoth values must exactly match the [supported model](#supported-models). The\nprovisioner checks them again before making any kernel change.\n\n\u003Ca id=\"run-the-provisioner\">\u003C\u002Fa>\n### 5. Run the recommended profile\n\n```sh\npython3 tools\u002Fprovision_portal.py --serial \"$PORTAL_IP:5555\" \\\n  --profile kiosk\n```\n\nThe `kiosk` profile installs Kiosk Satellite when needed, then configures its\nrequired permissions, Device Owner and HOME role. It also configures audio,\nfirmware and remote-wipe blocking, debloat, Meta-account removal, presence\noptimization, third-party app updates and non-expiring ADB authorization. These\ncore features do not need to be added as individual flags.\n\nAdd only the extra features you want:\n\n- `--presence-fps-cap 2` to reduce Meta's presence-analysis rate\n- `--dhcp-dns` or `--privacy-dns HOSTNAME` to change DNS behavior\n- `--system-theme-control light|dark` to enable and set live theme control\n- `--shizuku` to install Shizuku with automatic startup\n\nThe Portal reboots several times and ends with `PROVISION_OK` plus two\ndifferent verification boot IDs. If you do not want the complete profile, use\nthe individual commands in the reference below to build a custom setup.\n\n## Provisioning feature reference\n\nThe recommended `kiosk` profile already applies every feature labeled\n**Included in the kiosk profile**. Their individual sections remain useful for\nselective setups, technical details and rollback commands. Features labeled\n**Optional add-on** require their own flag.\n\n\u003Ca id=\"enable-only-persistent-wireless-adb\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Standalone setup:\u003C\u002Fstrong> Enable only persistent wireless ADB\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --persistent-wireless-adb\n```\n\nThis applies only wireless ADB persistence on TCP port 5555. It does not\nenable audio changes, debloat, Device Owner, presence optimization, Shizuku,\nor the other provisioning features. It also disables Android's authorization\ntimeout so computers you already approved do not lose access later. Wireless\nADB persistence is already installed automatically whenever another privileged\nprovisioning action runs; a new persistence install also disables the\nauthorization timeout.\n\nOn a stock Portal, continue manually enabling ADB in the Debug menu and running\n`adb -d tcpip 5555` after each provisioning reboot until the command prints\n`WIRELESS_ADB_OK`. Later reboots no longer require the USB host.\n\n\u003C\u002Fdetails>\n\u003Cp>\u003C\u002Fp>\n\n\u003Ca id=\"disable-adb-authorization-timeout\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Keep approved ADB computers authorized\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --disable-adb-auth-timeout\n```\n\nAndroid normally expires approved ADB host keys after a period of inactivity.\nThis sets `adb_allowed_connection_time` to `0`, which tells Android to retain\npreviously approved keys indefinitely. A new computer must still be approved on\nthe Portal; this does not disable ADB authentication. The provisioner also\nensures Android's `adb_enabled` framework setting is on so the authorization\nprompt can appear for that new computer. It saves the original connection-time\nsetting before changing it.\n\nOn every supported Portal target, privileged provisioning that removes the Meta\naccounts or selects non-expiring ADB authorization installs UID-1000 boot\nenforcement that restores `adb_enabled=1` if firmware changes it. This includes\n`--persistent-wireless-adb` and `--profile kiosk`. Portal 10-inch and Portal\nMini Omni firmware also use the same helper to recover adbd itself after Meta's\nlate boot rules stop it.\n\nThis standalone action uses ordinary ADB authority and does not run the root\nexploit or reboot the Portal.\n\n`--persistent-wireless-adb` applies this setting automatically. To restore the\nsaved timeout, run:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --restore-adb-auth-timeout\n```\n\n\u003C\u002Fdetails>\n\u003Cp>\u003C\u002Fp>\n\n\u003Ca id=\"install-kiosk-satellite\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Install Kiosk Satellite\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --install-kiosk-satellite\n```\n\nWhen Kiosk Satellite is missing, the provisioner reads the latest release from\nthe official [Kiosk Satellite repository](https:\u002F\u002Fgithub.com\u002Fjxlarrea\u002Fkiosk-satellite),\nselects the APK for the Portal's CPU architecture, verifies the file against\nthe SHA-256 digest published by GitHub, installs it and opens it once. It does\nnot replace or update an existing installation, so its app data is preserved.\nThis standalone action uses ordinary ADB authority and does not reboot or run\nthe root exploit.\n\nIn the complete `--profile kiosk` flow, installation happens before the\nprovisioner activates `KioskAdminReceiver`, assigns Device Owner and grants\npermissions.\n\n\u003C\u002Fdetails>\n\u003Cp>\u003C\u002Fp>\n\n\u003Ca id=\"disable-hardware-echo-cancellation-and-noise-suppression\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Disable hardware echo cancellation and noise suppression\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --audio\n```\n\nThe Portal's microphone array passes through firmware-owned voice processing\nbefore Android receives it. This action installs a native watchdog inside\nMeta's AIService and selects the controls used by each hardware backend.\n\nPortal Go and the other STAX\u002FDBMD builds keep these private DSP parameters at\nzero:\n\n- `AEC_ENABLE` (`3001`)\n- `NS_MODE` (`4001`), including residual-echo suppression\n\nPortal Mini and second-generation 10-inch Portal (`omni`) use the MH Acoustics\nMHA backend instead. On those devices the provisioner keeps the stereo capture\nengine active and patches the firmware tuning profiles to disable\ndouble-talk echo suppression, residual-echo suppression, and noise suppression\nin both post-processing paths. It validates the exact shipped blob before\nwriting, preserves a byte-for-byte stock backup, and restores the vendor block\ndevice's read-only state afterward. The restore action puts that stock blob\nback.\n\nThe change is system-wide, so every Android application receives audio without\nthose processing stages. On STAX devices, the watchdog reapplies the values\nafter AIService starts and repairs later firmware-side changes. On MHA devices,\nit reads the live hardware values and, if necessary, forces a temporary profile\ntransition so the tuning manager reloads the patched regular-capture profile.\nIt then verifies all nine suppression controls directly. The provisioner\nrequires real DSP readbacks on two boots. A later\n`--audio` run first checks the persistent\ninstallation marker and the running watchdog. If both are healthy, an\naudio-only command exits successfully without rebuilding, exploiting, or\nrebooting; when combined with other actions, only the audio installation is\nskipped.\n\nRestore Meta's original AIService loader, remove the watchdog, and restore the\nfirmware's AEC and NS parameter defaults with:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --restore-audio\n```\n\nThe restore uses the original loader saved during the first installation and\nrefuses to replace an unrelated file.\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"grant-kiosk-satellite-permissions\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Grant Kiosk Satellite permissions\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --kiosk-permissions\n```\n\nThis grants Kiosk Satellite access to the microphone, camera, location and\nshared storage; enables display-over-other-apps, system-settings and usage\naccess; grants the Portal-specific system-log access used by the built-in\nperson sensor; and exempts the app from battery optimization. The provisioner\nrestarts Kiosk Satellite after granting log access and verifies every grant.\n\nThis action does not enable or modify Android accessibility services. It uses\nordinary ADB shell authority and does not require the root exploit. The grants\nsurvive reboots and correctly signed application updates. Android revokes the\nruntime permissions if Kiosk Satellite's app data is cleared; rerun this action\nafter a data clear.\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"make-kiosk-satellite-the-device-owner\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Make Kiosk Satellite the Device Owner\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --device-owner\n```\n\nThis gives Kiosk Satellite Android's Device Owner role for user 0. Device Owner\nallows the kiosk to apply stronger device policies than an ordinary device\nadmin. The complete `--profile kiosk` installs the app when needed and\nactivates `KioskAdminReceiver` before this step. For a selective setup, run\n`--install-kiosk-satellite` first or install the app yourself; the Device Owner\npreflight activates the receiver.\n\nMeta accounts normally cause Android's `dpm set-device-owner` command to reject\nthe operation. The privileged installer writes the Android 10 owner record\nonly after checking that no other Device Owner exists. It saves the original\npolicy state under `\u002Fdata\u002Flocal\u002Ftmp\u002Fportal-device-owner-backup` and verifies\nboth DevicePolicyManager and `ro.device_owner=true` after reboot. There is no\nautomated Device Owner removal action in the provisioner.\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"use-kiosk-satellite-as-the-home-screen\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Use Kiosk Satellite as the home screen\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --kiosk-home\n```\n\nThis uses Kiosk Satellite's Device Owner authority to register its\ndisabled-by-default `HomeAlias` as Android's persistent HOME activity. Kiosk\nSatellite then starts directly after boot and receives every Home press. This\nalso prevents Meta's `AlohaInvalidOwnerHomeActivity` from covering the kiosk\nafter local Meta accounts are removed. Kiosk Satellite's built-in crash-loop\nfuse releases the HOME role automatically if the app repeatedly fails to\nstart. During provisioning and reboot verification, the provisioner repairs\nthe HOME selection automatically if Meta's launcher has reclaimed it.\n\nKiosk Satellite must already be Device Owner. The complete `--profile kiosk`\napplies the Device Owner record first and then configures HOME. Release the role\nand return to Android's remaining launcher resolution with:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --restore-kiosk-home\n```\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"disable-automatic-meta-firmware-updates\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Disable automatic Meta firmware updates\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --disable-updates\n```\n\nThis disables Meta's two OTA user-interface packages and installs a local\nMobileConfig override setting `firmware_ota_update_enable=false`. Shared update\ninfrastructure remains installed, but the native OTA daemon stays idle and\ndoes not discover or install firmware.\n\nThe provisioner verifies the disabled packages and requires Meta's own service\nto report the value from the local override on two boots. It refuses to replace\nan unrelated existing override. The original file state is recorded under\n`\u002Fdata\u002Flocal\u002Ftmp\u002Fportal-ota-backup`.\n\nRestore that exact override state and re-enable both OTA packages with:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --enable-updates\n```\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"block-metas-known-remote-wipe-receivers\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Block Meta's known remote-wipe receivers\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --block-remote-wipe\n```\n\nMeta's privileged `com.facebook.alohaservices.deviceadmin` package contains a\nfactory-reset receiver and a cloud-notification remote-wipe receiver. This\naction disables only those two components. The rest of the package remains\nenabled, and hardware or recovery-menu factory resets remain available.\n\nThe provisioner records the original state of each receiver, applies the\nchange through Android's Package Manager, and verifies that both receivers\nremain disabled across two boots. It does not claim to block every possible\nprivileged Android reset path; it blocks the two known Meta remote-wipe entry\npoints present in the supported firmware.\n\nRestore both receivers to their individually saved states with:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --restore-remote-wipe\n```\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"disable-unused-meta-applications\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Disable unused Meta applications\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --debloat\n```\n\nThe conservative debloat profile disables these packages for user 0:\n\n- Meta Analytics\n- Messenger\n- WhatsApp\n- Portal Feed\n- Superframe\n- Meta Contacts\n\nIt also disables the matching cloud and background components inside retained\nMeta packages. The exact inventories for every supported model are listed\nbelow: 196 are disabled on the tested Portal Go, Portal Mini,\nsecond-generation Portal 10-inch and second-generation Portal+ firmware, and\n194 are disabled on the original first-generation Portal. The tested\nfirst-generation Portal+ has a smaller installed package set and disables 39.\nPortal TV uses its own conservative 14-component profile.\nComponent-level targeting removes unused\nwork without disabling the camera, audio, presence, media, app-management,\nidentity, launcher, or WebView packages that the Portal and Kiosk Satellite\nstill need.\n\nOn every tested model, two firmware-owned MQTT entry points are deliberately\nretained because each self-enables before use; disabling either caused a\nservice restart loop during testing: `RegisteredMqttSystemBroadcastReceiver` in\n`com.facebook.aloha.system.device` and `MqttService` in\n`com.facebook.alohaservices.alohausers`. The remaining MQTT components are\ndisabled. To stop the retained core client from reaching Meta, apply a\nsource-specific router rule for the Portal or block `mqtt-mini.facebook.com`,\n`graph.facebook.com`, and `facebook.com` with the only DNS resolver advertised\nto the device. Android's opportunistic Private DNS can use any advertised\nresolver that accepts DNS over TLS, so a public fallback resolver can bypass a\nlocal DNS block list. Fixed-IP rules are brittle because Meta rotates these\nnames across its address space. The component list is maintained in\n`tools\u002Fmeta_debloat_components.py`.\n\n\u003Cdetails>\n\u003Csummary>Meta Portal Go, original Portal 10-inch, Portal Mini, Portal 10-inch (2nd generation) and Portal+ (2nd generation): up to 196 disabled components\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\nOn Portal Go firmware `5051355900018050`, Portal Mini and Portal 10-inch\nfirmware `3051355900018050`, and Portal+ firmware `4051355900018050`, the\nprovisioner disables the same 196 components. The two intentionally retained\nMQTT components are excluded from this inventory.\n\nThe original 10-inch Portal uses this inventory too. Its tested factory image\ncontains 194 of the entries; the two CNS health-monitor components are absent,\nso the provisioner records them as absent instead of trying to disable them.\n\n**Background workers (143)**\n\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.aloha.system.services\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.aloha.app.appmanager.common.periodicwork.PeriodicWorkGuardReceiver`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.aloha.app.appmanager.common.periodicwork.PeriodicWorkAlarmReceiver`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.aloha.app.appmanager.common.periodicwork.PeriodicWorkJobService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.aloha.app.appmanager.common.downloadmanager.impl.DownloadIdleService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.aloha.app.appmanager.appmanager.scheduler.background.SchedulerJobService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.alohaappmanager\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.alohaapps.launcher\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.alohaapps.personaluser\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.alohaservices.abilitymanager\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.alohaservices.player2\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n\n**Bug reporting (16)**\n\n- `com.facebook.aloha.system.services\u002Fcom.facebook.aloha.system.services.bugreporter.PillViewService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.aloha.system.bugreporter.receiver.MannerModeBroadcastReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.aloha.system.bugreporter.receiver.BugReportSystemBroadcastReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.aloha.system.bugreporter.receiver.BugReportNonSystemBroadcastReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.aloha.system.bugreporter.receiver.PortalTVReportScreenLauncherReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.aloha.system.bugreporter.receiver.TraceBroadcastReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.aloha.system.bugreporter.receiver.SmartCameraBroadcastReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.bugreporter.core.scheduler.AlarmsBroadcastReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.aloha.system.bugreporter.gui.BugReporterGuiService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.aloha.system.bugreporter.receiver.PushNotificationReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.aloha.system.bugreporter.core.ReportIntentService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.aloha.system.bugreporter.core.UploadStreamService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.bugreporter.core.scheduler.LollipopBugReportService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.alohacommon.bugreporterlib.AppLogsService`\n- `com.facebook.alohaapps.bugreporter\u002Fandroidx.work.impl.background.systemjob.SystemJobService`\n- `com.facebook.alohaapps.bugreporter\u002Fcom.facebook.aloha.system.bugreporter.bishop.BishopSupportService`\n\n**Diagnostics (15)**\n\n- `com.facebook.aloha.app.cameraeditor\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.aloha.cnshealthmonitor\u002Fcom.facebook.aloha.cnshealthmonitor.CNSHealthMonitorBroadcastReceiver`\n- `com.facebook.aloha.cnshealthmonitor\u002Fcom.facebook.aloha.cnshealthmonitor.CNSHealthMonitorService`\n- `com.facebook.aloha.system.device\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.aloha.system.services\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.aloha.wifidiagnostic\u002Fcom.facebook.aloha.wifidiagnostic.WifiDiagnosticBootReceiver`\n- `com.facebook.aloha.wifidiagnostic\u002Fcom.facebook.aloha.wifidiagnostic.WifiDiagnosticService`\n- `com.facebook.alohaappmanager\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.alohaapps.bugreporter\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.alohaapps.launcher\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.alohaapps.settings\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.alohaservices.abilitymanager\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.alohaservices.alohausers\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.alohaservices.player2\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.portal.aiservice\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n\n**Firebase (12)**\n\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.google.firebase.iid.FirebaseInstanceIdReceiver`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.google.firebase.components.ComponentDiscoveryService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.google.firebase.messaging.FirebaseMessagingService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.google.firebase.provider.FirebaseInitProvider`\n- `com.facebook.aloha.system.device\u002Fcom.google.firebase.iid.FirebaseInstanceIdReceiver`\n- `com.facebook.aloha.system.device\u002Fcom.google.firebase.components.ComponentDiscoveryService`\n- `com.facebook.aloha.system.device\u002Fcom.google.firebase.messaging.FirebaseMessagingService`\n- `com.facebook.aloha.system.device\u002Fcom.google.firebase.provider.FirebaseInitProvider`\n- `com.facebook.alohaservices.alohausers\u002Fcom.google.firebase.iid.FirebaseInstanceIdReceiver`\n- `com.facebook.alohaservices.alohausers\u002Fcom.google.firebase.components.ComponentDiscoveryService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.google.firebase.messaging.FirebaseMessagingService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.google.firebase.provider.FirebaseInitProvider`\n\n**MQTT (8)**\n\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.push.mqtt.service.MqttPushHelperService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.multiusermqtt.MultiuserMqttService`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.mqtt.service.MqttServiceV2`\n- `com.facebook.aloha.app.cameraeditor\u002Fcom.facebook.mqttlite.MqttService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.push.mqtt.receiver.BootCompleteBroadcastReceiver`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.mqtt.service.MqttServiceV2`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.multiusermqtt.MultiuserMqttService`\n- `com.facebook.alohaservices.alohausers\u002Fcom.facebook.push.mqtt.service.MqttPushHelperService`\n\n**Push notifications (2)**\n\n- `com.facebook.alohasdk.pushnotification\u002Fcom.facebook.alohasdk.pushnotification.PushNotificationBootReceiver`\n- `com.facebook.alohasdk.pushnotification\u002Fcom.facebook.alohasdk.pushnotification.PushNotificationService`\n\n\u003C\u002Fdetails>\n\u003Cp>\u003C\u002Fp>\n\u003Cdetails>\n\u003Csummary>Meta Portal+ (1st generation): 39 disabled components\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\nOn firmware `1041515800015050`, the provisioner disables 39 components.\n\n**Background workers (30)**\n\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.aloha.system.device\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics2.logger.legacy.uploader.HighPriUploadRetryReceiver`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics.appstatelogger.AppStateIntentService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.reportaproblem.base.bugreport.BugReportUploadService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics2.logger.service.LollipopUploadSafeService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics2.logger.legacy.uploader.Analytics2UploadService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics2.logger.legacy.uploader.LollipopUploadService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.conditionalworker.LollipopConditionalWorkerService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.analytics2.logger.legacy.uploader.AlarmBasedUploadService`\n\n**Diagnostics (3)**\n\n- `com.facebook.aloha.system.device\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.alohaapps.settings\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.portal.aiservice\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n\n**Firebase (4)**\n\n- `com.facebook.aloha.system.device\u002Fcom.google.firebase.iid.FirebaseInstanceIdReceiver`\n- `com.facebook.aloha.system.device\u002Fcom.google.firebase.components.ComponentDiscoveryService`\n- `com.facebook.aloha.system.device\u002Fcom.google.firebase.messaging.FirebaseMessagingService`\n- `com.facebook.aloha.system.device\u002Fcom.google.firebase.provider.FirebaseInitProvider`\n\n**Push notifications (2)**\n\n- `com.facebook.alohasdk.pushnotification\u002Fcom.facebook.alohasdk.pushnotification.PushNotificationBootReceiver`\n- `com.facebook.alohasdk.pushnotification\u002Fcom.facebook.alohasdk.pushnotification.PushNotificationService`\n\n\u003C\u002Fdetails>\n\u003Cp>\u003C\u002Fp>\n\u003Cdetails>\n\u003Csummary>Meta Portal TV: 14 disabled components\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\nOn firmware `2041515800015050`, the provisioner disables only the following\ncomponents confirmed present on Portal TV. Its smaller application inventory\ndoes not use the broader touchscreen Portal profile.\n\n**Background workers (8)**\n\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.alohaapps.settings\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.delayedworker.DelayedWorkerServiceReceiver`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.conditionalworker.ConditionalWorkerServiceReceiver`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.delayedworker.DelayedWorkerService`\n- `com.facebook.portal.aiservice\u002Fcom.facebook.conditionalworker.ConditionalWorkerService`\n\n**Diagnostics (3)**\n\n- `com.facebook.aloha.system.device\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.alohaapps.settings\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n- `com.facebook.portal.aiservice\u002Fandroidx.work.impl.diagnostics.DiagnosticsReceiver`\n\n**Firebase (3)**\n\n- `com.facebook.aloha.system.device\u002Fcom.google.firebase.iid.FirebaseInstanceIdReceiver`\n- `com.facebook.aloha.system.device\u002Fcom.google.firebase.messaging.FirebaseMessagingService`\n- `com.facebook.aloha.system.device\u002Fcom.google.firebase.provider.FirebaseInitProvider`\n\n\u003C\u002Fdetails>\n\u003Cp>\u003C\u002Fp>\nBefore changing package state, the provisioner saves the exact enabled,\ndisabled, or absent state of every package in\n`\u002Fdata\u002Flocal\u002Ftmp\u002Fportal-debloat-backup-v1.tsv` and every targeted component in\n`\u002Fdata\u002Flocal\u002Ftmp\u002Fportal-debloat-components-backup-v1.tsv`. Restore those saved\nstates with:\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --restore-bloat\n```\n\nBoth commands verify the retained camera, AIService, Kiosk Home, and WebView\npaths across two reboots.\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"remove-local-meta-accounts\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Remove local Meta accounts\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --remove-meta-accounts\n```\n\nThis removes the Portal-specific proxy SSO, platform-login, and private-owner\naccounts from Android AccountManager and Meta's local identity databases. It\nthen disables their three user-account authenticator components so firmware\ncannot immediately recreate the accounts. The hardware-identity authenticator\nand shared `alohausers` package stay enabled because camera startup,\nMobileConfig, and other Portal services depend on them.\n\nThe original account type and name inventory is saved at\n`\u002Fdata\u002Flocal\u002Ftmp\u002Fportal-meta-accounts-before-v1.tsv` and copied into the host\nlog directory. Tokens and full database contents are not backed up, so this\naction has no automated restore. Repeated runs are safe: once the accounts are\ngone and the authenticators are disabled, the tool only verifies the state.\n\nRemoving the final Meta owner account can make Portal firmware select its\nobsolete invalid-owner HOME screen. Use `--kiosk-home` after Kiosk Satellite is\nDevice Owner, or use `--profile kiosk`, to keep the account warning from taking\nfocus.\n\nMeta's production Debug page also builds its ADB row from the signed-in owner\nprofile. After the local Meta accounts are removed, that page may appear empty\neven though ADB remains enabled and wireless ADB remains available. Before\nremoving the accounts, the provisioner verifies Android's ADB framework is\nenabled so future host keys can still produce the normal confirmation dialog.\nTo open the firmware's full Debug page from an authorized ADB computer, run:\n\n```sh\nadb -s \"$PORTAL_IP:5555\" shell am start \\\n  -a com.facebook.aloha.system.settings.DEBUG_TAB\n```\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"reduce-aiservice-cpu-use-while-preserving-presence-detection\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Reduce AIService CPU use while preserving presence detection\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\nRun:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --optimize-presence\n```\n\nKiosk Satellite reads AIService's `Notify people presence` log to use the\nPortal's person detector without activating an application camera and its\non-screen camera LED. This profile keeps that detector, AIService's camera\nclient, tracking, and pose estimation active while disabling four downstream\nSmart Camera workloads:\n\n- background segmentation\n- liveness scoring\n- color-based re-identification\n- face-recognition-based re-identification\n\nDisabling Meta's background detector by itself lets Smart Camera leave the\npose pipeline on a narrow region of interest, which severely reduces presence\ncoverage. The profile also sets `enable_hardware_cropping=false`. AIService\nthen processes the uncropped camera source, preserving the Portal's full field\nof view without running the background-detector worker.\n\nOpen the Portal's physical camera cover and make sure its camera\u002Fmicrophone\nprivacy control is off before running this action. Meta intentionally stops\nthe AIService camera client while either hardware privacy control disables the\ncamera, so presence verification cannot pass in that state.\n\nThe provisioner requires an active AIService camera client, an allowed CAMERA\nAppOp, live analysis and region-of-interest frame delivery, a loaded frame\nprocessor, populated pose-estimator metrics, all five settings loaded as\nfalse, and hardware cropping absent from the active camera request on every\nverification boot. Those checks cover the same retained path\nthat updates AIService's world model and emits `Notify people presence`, so the\ntwo-reboot verification can run unattended. An actual presence event is\nreported as additional evidence when one occurs, but it is not required for a\nsuccessful run. On the tested Portal Go, the original cropped optimization\naveraged 22.1% of one core but reduced the usable field of view. The corrected\nfull-scene profile measured 35.5% in a five-minute sample, compared with 47.8%\nbefore optimization. Workload affects these figures, so treat them as a guide\nrather than a fixed saving.\n\nThe original settings-file state is stored under\n`\u002Fdata\u002Flocal\u002Ftmp\u002Fportal-presence-backup`. Restore it with:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --restore-presence-profile\n```\n\nThe installer and restore action use atomic file replacement, preserve the\napp's ownership and SELinux label, and refuse to overwrite an unrelated edit.\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"allow-kiosk-satellite-and-third-party-app-updates\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Included in the kiosk profile:\u003C\u002Fstrong> Allow Kiosk Satellite and third-party app updates\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --allow-app-updates\n```\n\nMeta registers `com.facebook.appverifier` as Android's package-verification\nagent. It rejects APKs whose certificates are outside Meta's private allowlist,\nincluding correctly signed Kiosk Satellite releases, with\n`INSTALL_FAILED_VERIFICATION_FAILURE`. This action saves the existing Android\nsetting and verifier-package state, sets `package_verifier_enable=0`, and\ndisables Meta's verifier package for user 0. The package state is the durable\ncontrol if Meta later rewrites the Android setting. The provisioner verifies\nboth states on two separate boots.\n\nThis action is independent of Shizuku. It allows updates installed through the\nnormal Android confirmation screen, Kiosk Satellite Device Owner, the optional\nupdate helper, or Shizuku. Android continues to require a matching application\nsignature for updates and continues to reject version downgrades. Meta's\nverifier package remains installed and can be restored to its saved state.\n\nRestore the saved Android setting and verifier-package state with:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --restore-app-verifier\n```\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"optional-presence-analysis-frame-rate-cap\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Optional add-on:\u003C\u002Fstrong> Presence-analysis frame-rate cap\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\nThe full-scene profile keeps Meta's analysis pipeline busy at its firmware\nrate. To reduce that remaining load, cap only its pose-analysis callback. Two\nframes per second is the tested balance for room-presence detection:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --presence-fps-cap 2\n```\n\nValid values are 1 through 10. This option automatically includes the tested\nfull-scene presence profile. It writes Meta's own analysis-throttle settings\nand installs a small local boot helper that applies them after each reboot,\nthen stops. Applying the setting briefly opens Meta's hidden AI settings\nactivity and immediately returns to the configured Home app.\n\nAndroid blocks an ordinary background app from opening that activity. The\nprovisioner therefore adds the one-shot activation to its narrowly scoped UID\n1000 boot helper. That helper waits for Android and AIService to settle, opens\nthe hidden activity, returns to Home, and exits when no persistent helper task\nremains. It does not depend on Shizuku, ADB, another computer, or network access\nafter installation. Both presence rollback commands remove the activation\nconfiguration; the shared helper remains only if another feature still uses\nit.\n\nThe cap is downstream of camera capture. Tests on Portal Go retained the\ncamera's normal `[8, 30]` target range while Meta logged a 2 FPS analysis rate.\nA first-generation Portal+ also retained its full field of view and live pose\npipeline at 2 FPS across two reboots. Kiosk Satellite RTSP uses a separate\nCamera2 capture and encoder path, so it remains free to stream at its configured\nframe rate. A live Portal Go test decoded 56 RTSP frames over 9.98 seconds,\nabout 5.5 FPS from the configured roughly 6 FPS stream, while Meta analysis\nremained at 2 FPS. The provisioner verifies the applied analysis rate, full\nfield of view, camera request, pose pipeline, and helper activation on two\nboots.\n\nRemove only the cap and helper while keeping the full-scene optimization:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --restore-presence-fps\n```\n\n`--restore-presence-profile` also removes the cap and helper before restoring\nthe complete original presence configuration.\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"configure-dns\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Optional add-on:\u003C\u002Fstrong> Configure local or filtering DNS\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\nTo resolve private LAN zones through the DNS servers advertised by the active\nnetwork, run:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --dhcp-dns\n```\n\nThis disables Android's opportunistic Private DNS mode. Android then uses the\nDNS servers and search domain supplied by DHCP and IPv6 router advertisements.\nIt does not force a particular server address, so the router must advertise\nthe intended local resolver. In `dumpsys connectivity`, `defaultIPv4DNS` is\nonly the firmware's fallback when a network supplies no resolver; the\n`DnsAddresses` field in the connected network's `LinkProperties` is the active\nserver list. `--status` reports both lists separately.\n\nAlternatively, configure a specific DNS-over-TLS resolver:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --privacy-dns dns.example.net\n```\n\nReplace `dns.example.net` with the DNS-over-TLS hostname of a resolver you\ncontrol or trust. The provisioner configures Android's strict Private DNS mode;\nthe resolver supplies the block list. This can reduce connections to unwanted\nMeta endpoints without modifying system certificates or installing a broad\nroot firewall. Confirm that the resolver permits the services Kiosk Satellite\nneeds before applying it fleet-wide.\n\nThe first DNS action saves both original Android settings. Restore them with:\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --restore-privacy-dns\n```\n\n\u003C\u002Fdetails>\n\n\u003Ca id=\"control-the-runtime-system-theme\">\u003C\u002Fa>\n\u003Cdetails>\n\u003Csummary>\u003Cstrong>Optional add-on:\u003C\u002Fstrong> Control the runtime system theme\u003C\u002Fsummary>\n\u003Cp>\u003C\u002Fp>\n\n```sh\npython3 tools\u002Fprovision_portal.py \\\n  --serial \"$PORTAL_IP:5555\" --system-theme-control dark\n```\n\nUse `light` instead of `dark` to switch back. On the locked Android 10 builds,\nthe first run installs a fixed-purpose controller through the provisioner's\nUID-1000 boot-helper mechanism. Later provisioner runs reuse it and switch the\nlive theme without another exploit or reboot. Android 9 builds already allow\nthe normal shell `cmd uimode` operation, so the provisioner uses that directly.\n\nThe","2026-10-31 04:26:22","CREATED_QUERY"]