#!/usr/bin/env bash # ============================================================ # Messages Mod+ Standalone Script # Fix RCS on rooted Android devices by reinstalling # Google Messages as a user-space app # # Run from a computer with ADB connected to a rooted device # ============================================================ set -euo pipefail # ---- USER CONFIGURABLE VARIABLES ---- # Set these manually, or leave empty for auto-detection MSG_PKG="" # e.g. "com.google.android.apps.messaging" BACKUP_DIR="" # e.g. "./messages_backup" # ---- END USER CONFIG ---- # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' log() { echo -e "${BLUE}[*]${NC} $1"; } ok() { echo -e "${GREEN}[+]${NC} $1"; } warn() { echo -e "${YELLOW}[!]${NC} $1"; } err() { echo -e "${RED}[-]${NC} $1"; } hdr() { echo -e "\n${BOLD}${CYAN}=== $1 ===${NC}\n"; } su_cmd() { adb shell su -c "$1" 2>&1 } check_adb() { if ! command -v adb &>/dev/null; then err "ADB not found in PATH" exit 1 fi local devices devices=$(adb devices | grep -w "device" | grep -v "List") if [ -z "$devices" ]; then err "No ADB device connected" exit 1 fi local serial serial=$(echo "$devices" | head -1 | awk '{print $1}') ok "Device connected: ${serial}" } check_root() { local whoami whoami=$(su_cmd 'id -u' | tr -d '[:space:]') if [ "$whoami" != "0" ]; then err "Root shell not available (su failed)" err "Make sure KernelSU, Magisk, or another root solution is active" exit 1 fi ok "Root shell verified" } auto_detect() { log "Auto-detecting Google Messages package..." # Try the standard package name local found found=$(adb shell pm list packages 2>/dev/null | grep "com.google.android.apps.messaging" || true) if [ -n "$found" ]; then MSG_PKG="com.google.android.apps.messaging" ok "Found: ${MSG_PKG}" else # Broader search warn "Standard package not found, searching..." found=$(adb shell pm list packages 2>/dev/null | grep -i "messaging\|messages" || true) if [ -n "$found" ]; then echo "" echo "Found messaging packages:" echo "$found" | sed 's/package:/ /' | nl echo "" read -rp "Enter the number of the correct package (or type it manually): " choice if [[ "$choice" =~ ^[0-9]+$ ]]; then MSG_PKG=$(echo "$found" | sed 's/package://' | sed -n "${choice}p" | tr -d '[:space:]') else MSG_PKG="$choice" fi else err "No messaging packages found on device" exit 1 fi fi BACKUP_DIR="${BACKUP_DIR:-./messages_backup_$(date +%Y%m%d)}" } manual_config() { echo "" read -rp "Enter Messages package name [com.google.android.apps.messaging]: " input_pkg MSG_PKG="${input_pkg:-com.google.android.apps.messaging}" read -rp "Enter local backup directory [./messages_backup]: " input_dir BACKUP_DIR="${input_dir:-./messages_backup}" # Verify package exists if ! adb shell pm list packages | grep -q "$MSG_PKG"; then err "Package '${MSG_PKG}' not found on device" exit 1 fi ok "Package verified: ${MSG_PKG}" } backup_databases() { hdr "Backing Up Databases" mkdir -p "${BACKUP_DIR}/databases" # SMS/MMS local sms_db="/data/data/com.android.providers.telephony/databases/mmssms.db" log "Backing up SMS/MMS database..." adb shell su -c "cat '${sms_db}'" > "${BACKUP_DIR}/databases/mmssms.db" 2>/dev/null && \ ok "SMS/MMS: $(du -h "${BACKUP_DIR}/databases/mmssms.db" | cut -f1)" || \ warn "SMS/MMS database not found or empty" # RCS / Bugle local rcs_db="/data/data/${MSG_PKG}/databases/bugle_db" log "Backing up RCS database..." adb shell su -c "cat '${rcs_db}'" > "${BACKUP_DIR}/databases/bugle_db.db" 2>/dev/null && \ ok "RCS: $(du -h "${BACKUP_DIR}/databases/bugle_db.db" | cut -f1)" || \ warn "RCS database not found or empty" # Remove zero-byte files from failed backups find "${BACKUP_DIR}/databases" -size 0 -delete 2>/dev/null || true } pull_apks() { hdr "Pulling APK Splits" mkdir -p "${BACKUP_DIR}/apks" local apk_paths apk_paths=$(adb shell su -c "pm path '${MSG_PKG}'" | sed 's/package://' | tr -d '\r') if [ -z "$apk_paths" ]; then err "Could not find APK paths for ${MSG_PKG}" exit 1 fi local count=0 while IFS= read -r apk_path; do apk_path=$(echo "$apk_path" | tr -d '[:space:]') [ -z "$apk_path" ] && continue local apk_name apk_name=$(basename "$apk_path") log "Pulling ${apk_name}..." adb shell su -c "cat '${apk_path}'" > "${BACKUP_DIR}/apks/${apk_name}" local size size=$(du -h "${BACKUP_DIR}/apks/${apk_name}" | cut -f1) ok " ${apk_name} (${size})" count=$((count + 1)) done <<< "$apk_paths" ok "Pulled ${count} APK split(s)" } disable_system() { hdr "Disabling System Messages" log "Disabling ${MSG_PKG}..." local result result=$(adb shell su -c "pm disable-user --user 0 '${MSG_PKG}'" 2>&1) echo " ${result}" if echo "$result" | grep -q "disabled"; then ok "System app disabled" else warn "Disable command returned unexpected output" fi } reinstall_userspace() { hdr "Reinstalling as User-Space App" local apk_files apk_files=$(ls -1 "${BACKUP_DIR}/apks/"*.apk 2>/dev/null) local apk_count apk_count=$(echo "$apk_files" | wc -l) if [ -z "$apk_files" ] || [ "$apk_count" -eq 0 ]; then err "No APK files found in ${BACKUP_DIR}/apks/" exit 1 fi log "Installing ${apk_count} APK split(s)..." local install_args="" while IFS= read -r apk; do install_args="${install_args} ${apk}" done <<< "$apk_files" local result if [ "$apk_count" -gt 1 ]; then result=$(adb install-multiple $install_args 2>&1) else result=$(adb install $install_args 2>&1) fi echo " ${result}" if echo "$result" | grep -qi "success"; then ok "Installation successful" else err "Installation failed" warn "Attempting to re-enable system app..." adb shell pm enable "$MSG_PKG" 2>/dev/null exit 1 fi } reenable_package() { hdr "Re-enabling Package" local result result=$(adb shell pm enable "$MSG_PKG" 2>&1) echo " ${result}" ok "Package enabled" } verify() { hdr "Verification" local flags flags=$(adb shell su -c "dumpsys package '${MSG_PKG}'" | grep "pkgFlags" | head -1) if echo "$flags" | grep -q "UPDATED_SYSTEM_APP"; then ok "Messages is running as UPDATED_SYSTEM_APP (user-space)" echo "" echo -e "${GREEN}${BOLD} Messages Mod+ applied successfully!${NC}" echo "" echo " Next steps on your device:" echo " 1. Open Google Messages" echo " 2. Set as default SMS app if prompted" echo " 3. Grant permissions" echo " 4. RCS should provision normally" echo "" else warn "Package flags: ${flags}" warn "State may not be as expected - verify on device" fi } revert_to_stock() { hdr "Reverting to Stock" log "Removing user-space updates..." adb shell pm uninstall-updates "$MSG_PKG" 2>&1 || true adb shell pm enable "$MSG_PKG" 2>/dev/null local flags flags=$(adb shell su -c "dumpsys package '${MSG_PKG}'" | grep "pkgFlags" | head -1) if echo "$flags" | grep -q "UPDATED_SYSTEM_APP"; then warn "Revert may not have completed fully" else ok "Messages reverted to stock system app" fi } show_menu() { echo "" echo -e "${BOLD}${CYAN}Messages Mod+${NC}" echo -e "Fix RCS on rooted Android devices" echo "" echo " 1) Apply mod (full process)" echo " 2) Backup databases only" echo " 3) Revert to stock" echo " 4) Check status" echo " 5) Exit" echo "" read -rp "Select option [1-5]: " choice echo "" return "$choice" } show_status() { hdr "Current Status" local flags flags=$(adb shell su -c "dumpsys package '${MSG_PKG}'" 2>/dev/null | grep "pkgFlags" | head -1 || echo "not found") local code_path code_path=$(adb shell su -c "dumpsys package '${MSG_PKG}'" 2>/dev/null | grep "codePath=" | head -1 | sed 's/.*codePath=//' || echo "unknown") local enabled enabled=$(adb shell pm list packages -e 2>/dev/null | grep -q "$MSG_PKG" && echo "Yes" || echo "No") echo " Package: ${MSG_PKG}" echo " Path: ${code_path}" echo " Enabled: ${enabled}" echo " Flags: ${flags}" if echo "$flags" | grep -q "UPDATED_SYSTEM_APP"; then ok "State: MODDED (user-space)" elif echo "$flags" | grep -q "SYSTEM"; then warn "State: SYSTEM (stock)" else log "State: Unknown" fi } # ============================================================ # Main # ============================================================ echo "" echo -e "${BOLD}${CYAN}╔══════════════════════════════════╗${NC}" echo -e "${BOLD}${CYAN}║ Messages Mod+ v1.0.0 ║${NC}" echo -e "${BOLD}${CYAN}║ Fix RCS on Rooted Devices ║${NC}" echo -e "${BOLD}${CYAN}╚══════════════════════════════════╝${NC}" echo "" # Preflight check_adb check_root # Detection mode echo "" echo "Configuration mode:" echo " 1) Auto-detect (recommended)" echo " 2) Manual" echo "" read -rp "Select [1/2]: " mode case "$mode" in 2) manual_config ;; *) auto_detect ;; esac BACKUP_DIR="${BACKUP_DIR:-./messages_backup_$(date +%Y%m%d)}" mkdir -p "$BACKUP_DIR" log "Backup directory: ${BACKUP_DIR}" # Main menu loop while true; do show_menu opt=$? case "$opt" in 1) backup_databases pull_apks disable_system reinstall_userspace reenable_package verify ;; 2) backup_databases ;; 3) revert_to_stock ;; 4) show_status ;; 5) echo "Bye!" exit 0 ;; *) warn "Invalid option" ;; esac done