I debloated my dad's vivo phone with ADB...
What started as "let me just remove a few annoying apps" turned into a multi-day saga: OEM-locked packages, case-sensitivity landmines, a phantom hidden game, and a crash course in how much telemetry lives on a stock Android phone. Commands, failures, and the reasoning included.
The setup
The target: a Vivo phone on FuntouchOS with years of accumulated bloat - vivo's own system apps, a stack of Google apps nobody asked for, background noise from both. No root. Just ADB, a USB cable, and a Windows machine.
adb devices
List of devices attached
137*********4BI device
Device authorized, ready. Developer Options on, USB Debugging on, RSA prompt accepted on the phone.
The core commands
Everything runs on two subcommands:
adb shell pm uninstall --user 0 <package.name>
adb shell pm disable-user --user 0 <package.name>
--user 0 doesn't delete the APK from the system partition. It removes the app from your user profile. On a single-user phone that's functionally identical to uninstalling - app gone, stopped, no updates. But the APK still exists at system level, which is why this is safe to experiment with: worst case, a factory reset restores everything.
Disabling is the reversible version:
adb shell pm disable-user --user 0 <package.name>
adb shell pm enable <package.name> # to undo
adb shell cmd package install-existing <package.name> # alternate undo
Finding out what's actually installed
You need real package names, not display names:
adb shell pm list packages -f # all packages, with install path
adb shell pm list packages -3 # third-party apps only
The -f flag matters. The install path tells you how embedded a package is:
/data/app/...→ normal install. Safe territory./system/app/...→ system app, usually a removable extra./system/priv-app/...→ privileged. Core OS or carrier function. Tread carefully.
For grepping (no grep on CMD, use findstr):
adb shell pm list packages | findstr /i "google music tv"
A three-tier safety framework
Hundreds of package names across two ecosystems - vivo's bloat, Google's bundling. Everything sorted into three tiers:
Tier 1 - safe to uninstall. Vivo extras (magazine lock screen, app recommendations, redundant widgets, bundled office viewer, live wallpapers) and optional Google apps (YouTube, Gemini, Docs/Sheets/Slides, Digital Wellbeing, AR Core). All reinstallable from the Play Store.
Tier 2 - disable, don't uninstall. Anything that might be a default handler (dialer, contacts, calendar, gallery) or that other system tools might depend on (vivo's phone manager, AI engine). Same practical effect - hidden, stopped, silent - without severing it.
Tier 3 - do not touch. Play Services and its dependencies, the network stack, WebView, the keyboard, VoLTE/VoWiFi components, OTA services, setup wizard, permission controller. A mistake here means a bootloop or a phone that can't call.
Where it actually broke
Case sensitivity will humble you
adb shell pm uninstall --user 0 com.vivo.tips
Failure [not installed for 0]
The package was right there in pm list packages. As com.vivo.Tips - capital T. Package names are case-sensitive, and the error gives zero hint. "Not installed" reads like it doesn't exist; really it's a one-character typo.
adb shell pm uninstall --user 0 com.vivo.Tips
Worked immediately.
DELETE_FAILED_USER_RESTRICTED
adb shell pm uninstall --user 0 com.bbk.cloud
Failure [DELETE_FAILED_USER_RESTRICTED]
Not a naming issue - a deliberate OEM policy lock. Some manufacturers flag packages tied to accounts, cloud backup, or anti-theft as non-removable at user level. Likely reasoning: stop someone disabling tracking on a stolen phone.
Fallback chain:
adb shell pm disable-user --user 0 com.bbk.cloud # try disable first
adb shell pm hide --user 0 com.bbk.cloud # weaker restriction, often gets through
If even those fail, go behavioral: sign out of the account, turn off sync, leave the package installed but inert.
The hidden game that stayed hidden
A game was reportedly hidden via vivo's AppLock hide feature. Keyword searches - free, fire, freefire, garena, dts - nothing.
The reasoning chain, in order:
- Launcher-only hiding. Vivo's hide usually just removes the icon; the package should still list. Full unfiltered list: clean.
- Second user profile. Vivo supports App Clone / Second Space - a separate Android user ADB won't see under user 0.
adb shell pm list usersshowed a single user (UserInfo{0:Owner:c13}). Ruled out. - Obfuscated naming. Free Fire's studio is "111dots," not Garena - so
com.dts.freefirethwas the expected name. Still nothing. - Full third-party list, eyeballed.
adb shell pm list packages -3- about 30 apps, no game under any name.
So ADB never saw it - but NextDNS did. The game's domains kept showing up in the phone's DNS logs, meaning it was still installed, still running, still phoning home, just invisible to every pm list variant I tried. AppLock's hide on this skin goes deeper than removing a launcher icon; whatever it does, user-0 package enumeration doesn't see through it.
I gave up there. Short of digging through vivo's AppLock storage by hand, there was no ADB-side move left. The DNS block stays on and the game stays network-broken - good enough for a phone that isn't mine.
Sometimes the tool can't see what the OS is hiding, and the logs are the only honest witness.
Telemetry packages, specifically
Once the obvious bloat was gone: which remaining packages were data collection rather than functionality.
com.google.android.feedback- crash/bug-report uploader. Safe to remove; occasional cosmetic error dialog if something else crashes and tries to invoke it.com.google.android.gms.location.history- Maps Timeline module. Removable if Timeline isn't used.com.google.mainline.telemetry- near-empty stub reporting version numbers so Play System Updates sync metrics modules. No functionality of its own. Community lists are split on it, so disable rather than uninstall.
Honestly: removing these individually barely moves the needle. The bulk of collection runs through Play Services itself, which isn't safely removable without root. For actual tracking reduction, the higher-leverage moves are in Settings - Ads Personalization off, Location History off as a service (not just removing the app), Usage & Diagnostics off for Google and vivo.
Verifying it worked
The proof wasn't the package list - it was network logs. Phone routed through NextDNS with logging on: request volume dropped noticeably, and what remained was legible - WhatsApp calls, Play license checks, NTP, one Firebase logging call from an app with baked-in analytics. Before: a dozen vivo services phoning home. A shorter app drawer is cosmetic; measurably less background chatter is the actual result.
Tools worth knowing about
By hand works for one phone; it doesn't scale. UAD-ng (Universal Android Debloater NG) is the maintained continuation of UAD - a Rust GUI wrapping the same pm commands, backed by a community database of 1000+ packages with safety ratings (Recommended / Advanced / Expert / Unsafe).
Open source, can't touch anything ADB couldn't, useful second opinion - but a blind spot for OEM-specific services like vivo's, where disabling the UI doesn't necessarily stop the underlying service. Cross-reference, not gospel, especially on less-mainstream skins.
What this was really about
Framed narrowly: bloatware removal. Framed honestly: debugging with unusually good error messages and a physical feedback loop - you either broke your dad's phone or you didn't.
- Read the exact error, not the summary. "Not installed" and "USER_RESTRICTED" look alike until you check - one's a typo, one's a policy lock, totally different fixes.
- Prefer reversible actions. Disable-first, uninstall-later, whenever the risk isn't fully known.
- Know when the tool has no more answers. ADB couldn't see through AppLock's hiding; the DNS logs could. I stopped there instead of escalating past what the problem was worth.
- Verify with an independent signal. The package list said it worked. The network logs proved it.
No root, no custom ROMs, nothing exotic. ADB, patience, and treating each failure message as information instead of a dead end.