commit 0953b1d929ba0ef9e037ad9d743925413b4ab314 Author: sssnake Date: Fri Apr 3 07:12:16 2026 -0700 Initial release v1.0.0 - Messages Mod+ KernelSU-Next module diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..365bc6d --- /dev/null +++ b/LICENSE @@ -0,0 +1,33 @@ +Messages Mod+ License + +Copyright (c) 2026 SetecLabs + +Permission is granted, free of charge, to any person obtaining a copy of +this software and associated files (the "Software"), to use the Software +for personal, non-commercial purposes only. + +The following restrictions apply: + +1. You may NOT redistribute, share, or otherwise distribute the Software + or any portion of it without prior written approval from the copyright + holder. + +2. You may NOT modify, adapt, or create derivative works based on the + Software without prior written approval from the copyright holder. + +3. You may NOT use the Software for any commercial purpose, or incorporate + it into any product or service offered to others, without prior written + approval from the copyright holder. + +4. This license notice must be included in all copies or substantial + portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +For licensing inquiries or approval requests, contact: SetecLabs diff --git a/README.md b/README.md new file mode 100644 index 0000000..1cd2032 --- /dev/null +++ b/README.md @@ -0,0 +1,91 @@ +# Messages Mod+ + +A KernelSU-Next module that fixes RCS (Rich Communication Services) on rooted Android devices by reinstalling Google Messages as a user-space app. + +## The Problem + +On rooted devices (KernelSU, Magisk, etc.), Google Messages installed as a system app can experience persistent RCS failures — even when Play Integrity passes at the STRONG level. The system-level installation hooks into the telephony stack differently than a user-space app, and this can cause RCS provisioning and registration to silently fail or intermittently break. + +## How It Works + +The module disables the system copy of Google Messages and reinstalls it as a user-space update. Android treats it as an `UPDATED_SYSTEM_APP` — the system base remains dormant while the active copy lives in `/data/app/` and behaves like a regular user-installed application. This difference in how the app is loaded and permissioned resolves the RCS issues. + +The original system APK stays untouched in `/product/priv-app/` — it only becomes active again if you explicitly revert. + +## Features + +### KernelSU Module +- **Action Button**: One-tap apply — disables system Messages, reinstalls as user-space +- **WebUI Dashboard** with: + - Live status display (MODDED / SYSTEM / NOT INSTALLED) + - SMS/MMS database backup & restore + - RCS database backup & restore + - Message attachments backup (photos, videos, media) + - Per-backup restore and delete + - Revert to stock with one tap +- **Auto-revert** on module uninstall +- All backups stored at `/sdcard/MessagesModPlus/` + +### Standalone Script +- Runs from a computer via ADB +- Auto-detect or manual package configuration +- Interactive menu with colored output +- Same full functionality as the module + +## Installation + +### KernelSU-Next Module +1. Download `MessagesModPlus-v1.0.0.zip` from Releases +2. Open KernelSU Manager +3. Go to Modules > Install from storage +4. Select the zip file +5. Open the module's WebUI or press the Action button + +### Standalone Script (via ADB) +```bash +chmod +x messages_mod_standalone.sh +./messages_mod_standalone.sh +``` + +Requirements: +- ADB connected to a rooted device +- Root shell access (KernelSU, Magisk, etc.) + +## After Applying + +1. Open Google Messages on your device +2. Set it as the default SMS app if prompted +3. Grant all requested permissions +4. RCS should provision normally + +## Reverting + +Three ways to revert: +- **WebUI**: Tap "Revert to Stock" +- **KernelSU Manager**: Remove the module (auto-reverts via uninstall.sh) +- **Standalone**: Select option 3 from the menu + +## File Structure + +``` +MessagesModPlus/ +├── module.prop # Module metadata +├── customize.sh # Installer +├── action.sh # Action button - runs apply +├── uninstall.sh # Auto-revert on module removal +├── scripts/ +│ └── messages_mod.sh # Core operations (all commands) +├── webroot/ +│ └── index.html # WebUI dashboard +└── messages_mod_standalone.sh # Standalone ADB script +``` + +## Compatibility + +- Tested on Pixel devices with KernelSU-Next +- Should work with any rooted Android device running Google Messages +- Requires Android 10+ (API 29+) + +## License + +Free for personal use. Redistribution, modification, or use beyond personal purposes requires approval. See LICENSE for full terms. diff --git a/action.sh b/action.sh new file mode 100755 index 0000000..a9994ff --- /dev/null +++ b/action.sh @@ -0,0 +1,14 @@ +#!/system/bin/sh +# Messages Mod+ - Action Button Handler +# Runs the main mod: disable system Messages, reinstall as user-space + +MODDIR="${0%/*}" +SCRIPT="${MODDIR}/scripts/messages_mod.sh" + +if [ ! -f "$SCRIPT" ]; then + echo "Error: messages_mod.sh not found" + exit 1 +fi + +export MODDIR +sh "$SCRIPT" apply diff --git a/customize.sh b/customize.sh new file mode 100755 index 0000000..60fa99b --- /dev/null +++ b/customize.sh @@ -0,0 +1,35 @@ +#!/system/bin/sh +# Messages Mod+ - Module Installer + +SKIPUNZIP=1 + +ui_print " " +ui_print " =============================" +ui_print " Messages Mod+" +ui_print " Fix RCS on Rooted Devices" +ui_print " =============================" +ui_print " " + +# Extract module files +ui_print "- Extracting module files..." +unzip -o "$ZIPFILE" -x 'META-INF/*' -d "$MODPATH" >&2 + +# Set permissions +ui_print "- Setting permissions..." +set_perm_recursive "$MODPATH" 0 0 0755 0644 +set_perm "$MODPATH/scripts/messages_mod.sh" 0 0 0755 +set_perm "$MODPATH/action.sh" 0 0 0755 + +# Create backup directory on internal storage +mkdir -p /sdcard/MessagesModPlus/sms +mkdir -p /sdcard/MessagesModPlus/rcs +mkdir -p /sdcard/MessagesModPlus/attachments +mkdir -p /sdcard/MessagesModPlus/apks + +ui_print " " +ui_print "- Backup directory: /sdcard/MessagesModPlus/" +ui_print " " +ui_print "- Installation complete!" +ui_print "- Open the module's WebUI to apply the mod" +ui_print "- Or press the Action button for quick apply" +ui_print " " diff --git a/messages_mod_standalone.sh b/messages_mod_standalone.sh new file mode 100755 index 0000000..707f164 --- /dev/null +++ b/messages_mod_standalone.sh @@ -0,0 +1,366 @@ +#!/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 diff --git a/module.prop b/module.prop new file mode 100644 index 0000000..8c98e20 --- /dev/null +++ b/module.prop @@ -0,0 +1,6 @@ +id=messages_mod_plus +name=Messages Mod+ +version=v1.0.0 +versionCode=100 +author=SetecLabs +description=Fix RCS on rooted devices by reinstalling Google Messages as a user-space app. Includes backup/restore for SMS, MMS, RCS databases and attachments. diff --git a/scripts/messages_mod.sh b/scripts/messages_mod.sh new file mode 100755 index 0000000..053386b --- /dev/null +++ b/scripts/messages_mod.sh @@ -0,0 +1,485 @@ +#!/system/bin/sh +# Messages Mod+ - Main Operations Script +# Runs on-device with root privileges +# Usage: messages_mod.sh [args] + +MODDIR="${MODDIR:-$(dirname "$(dirname "$(readlink -f "$0")")")}" +BACKUP_DIR="/sdcard/MessagesModPlus" +MSG_PKG="com.google.android.apps.messaging" +TELEPHONY_PKG="com.android.providers.telephony" +CARRIER_PKG="com.google.android.ims" + +SMS_DB="/data/data/${TELEPHONY_PKG}/databases/mmssms.db" +RCS_DB="/data/data/${MSG_PKG}/databases/bugle_db" +ATTACH_DIR="/data/data/${MSG_PKG}/files" + +log() { echo "[MessagesModPlus] $1"; } +err() { echo "[MessagesModPlus:ERROR] $1" >&2; } +timestamp() { date +%Y%m%d_%H%M%S; } + +ensure_backup_dir() { + mkdir -p "${BACKUP_DIR}/sms" "${BACKUP_DIR}/rcs" "${BACKUP_DIR}/attachments" "${BACKUP_DIR}/apks" +} + +get_apk_paths() { + pm path "$MSG_PKG" 2>/dev/null | sed 's/^package://' +} + +get_system_apk_path() { + dumpsys package "$MSG_PKG" | grep "codePath=" | grep -E "/system|/product|/system_ext|/vendor" | head -1 | sed 's/.*codePath=//' | tr -d ' ' +} + +is_system_app() { + dumpsys package "$MSG_PKG" | grep "pkgFlags" | head -1 | grep -q "SYSTEM" +} + +is_updated_system_app() { + dumpsys package "$MSG_PKG" | grep "pkgFlags" | head -1 | grep -q "UPDATED_SYSTEM_APP" +} + +is_package_enabled() { + pm list packages -e | grep -q "$MSG_PKG" +} + +get_status() { + local status="unknown" + local system_path="" + local user_path="" + local enabled="false" + + if ! pm list packages | grep -q "$MSG_PKG"; then + echo "NOT_INSTALLED|none|none|false" + return + fi + + system_path=$(get_system_apk_path) + user_path=$(dumpsys package "$MSG_PKG" | grep "codePath=" | grep "/data/app" | head -1 | sed 's/.*codePath=//' | tr -d ' ') + + if is_package_enabled; then + enabled="true" + fi + + if is_updated_system_app; then + status="MODDED" + elif is_system_app; then + status="SYSTEM" + else + status="USER" + fi + + echo "${status}|${system_path:-none}|${user_path:-none}|${enabled}" +} + +cmd_status() { + local info + info=$(get_status) + local state=$(echo "$info" | cut -d'|' -f1) + local sys_path=$(echo "$info" | cut -d'|' -f2) + local usr_path=$(echo "$info" | cut -d'|' -f3) + local enabled=$(echo "$info" | cut -d'|' -f4) + + echo "STATE=${state}" + echo "SYSTEM_PATH=${sys_path}" + echo "USER_PATH=${usr_path}" + echo "ENABLED=${enabled}" + + # Backup info + local sms_count=0 + local rcs_count=0 + local attach_count=0 + [ -d "${BACKUP_DIR}/sms" ] && sms_count=$(ls -1 "${BACKUP_DIR}/sms"/*.db 2>/dev/null | wc -l) + [ -d "${BACKUP_DIR}/rcs" ] && rcs_count=$(ls -1 "${BACKUP_DIR}/rcs"/*.db 2>/dev/null | wc -l) + [ -d "${BACKUP_DIR}/attachments" ] && attach_count=$(ls -1d "${BACKUP_DIR}/attachments"/*/ 2>/dev/null | wc -l) + echo "SMS_BACKUPS=${sms_count}" + echo "RCS_BACKUPS=${rcs_count}" + echo "ATTACH_BACKUPS=${attach_count}" +} + +cmd_backup_sms() { + ensure_backup_dir + if [ ! -f "$SMS_DB" ]; then + err "SMS database not found at ${SMS_DB}" + return 1 + fi + + local ts=$(timestamp) + local dest="${BACKUP_DIR}/sms/mmssms_${ts}.db" + + # Force a checkpoint so WAL data is flushed + cp "$SMS_DB" "$dest" 2>/dev/null + [ -f "${SMS_DB}-wal" ] && cp "${SMS_DB}-wal" "${dest}-wal" 2>/dev/null + [ -f "${SMS_DB}-journal" ] && cp "${SMS_DB}-journal" "${dest}-journal" 2>/dev/null + + if [ -f "$dest" ]; then + local size=$(du -h "$dest" | cut -f1) + log "SMS backup saved: ${dest} (${size})" + echo "BACKUP=${dest}" + return 0 + else + err "Failed to create SMS backup" + return 1 + fi +} + +cmd_backup_rcs() { + ensure_backup_dir + if [ ! -f "$RCS_DB" ]; then + err "RCS database not found at ${RCS_DB}" + return 1 + fi + + local ts=$(timestamp) + local dest="${BACKUP_DIR}/rcs/bugle_db_${ts}.db" + + cp "$RCS_DB" "$dest" 2>/dev/null + [ -f "${RCS_DB}-wal" ] && cp "${RCS_DB}-wal" "${dest}-wal" 2>/dev/null + [ -f "${RCS_DB}-journal" ] && cp "${RCS_DB}-journal" "${dest}-journal" 2>/dev/null + + if [ -f "$dest" ]; then + local size=$(du -h "$dest" | cut -f1) + log "RCS backup saved: ${dest} (${size})" + echo "BACKUP=${dest}" + return 0 + else + err "Failed to create RCS backup" + return 1 + fi +} + +cmd_backup_attachments() { + ensure_backup_dir + if [ ! -d "$ATTACH_DIR" ]; then + err "Attachments directory not found at ${ATTACH_DIR}" + return 1 + fi + + local ts=$(timestamp) + local dest="${BACKUP_DIR}/attachments/${ts}" + mkdir -p "$dest" + + # Copy all media/attachment files + local count=0 + + # bugle attachments + if [ -d "/data/data/${MSG_PKG}/files/photoEditor" ]; then + cp -r "/data/data/${MSG_PKG}/files/photoEditor" "$dest/" 2>/dev/null + fi + + # Main media storage used by Messages + local media_dir="/data/user_de/0/${MSG_PKG}/files" + if [ -d "$media_dir" ]; then + cp -r "$media_dir" "$dest/user_de_files" 2>/dev/null + fi + + # MMS parts (images, videos, audio from MMS) + local parts_dir="/data/data/${TELEPHONY_PKG}/app_parts" + if [ -d "$parts_dir" ]; then + cp -r "$parts_dir" "$dest/mms_parts" 2>/dev/null + fi + + # Also grab from the standard media location + local bugle_media="/data/data/${MSG_PKG}/cache" + if [ -d "$bugle_media" ]; then + cp -r "$bugle_media" "$dest/cache" 2>/dev/null + fi + + count=$(find "$dest" -type f 2>/dev/null | wc -l) + local size=$(du -sh "$dest" 2>/dev/null | cut -f1) + log "Attachments saved: ${dest} (${count} files, ${size})" + echo "BACKUP=${dest}" + echo "FILE_COUNT=${count}" + return 0 +} + +cmd_restore_sms() { + local backup_file="$1" + if [ -z "$backup_file" ]; then + # Use most recent backup + backup_file=$(ls -t "${BACKUP_DIR}/sms"/*.db 2>/dev/null | head -1) + fi + + if [ -z "$backup_file" ] || [ ! -f "$backup_file" ]; then + err "No SMS backup found" + return 1 + fi + + # Stop telephony provider temporarily + am force-stop "$TELEPHONY_PKG" 2>/dev/null + + cp "$backup_file" "$SMS_DB" + [ -f "${backup_file}-wal" ] && cp "${backup_file}-wal" "${SMS_DB}-wal" + [ -f "${backup_file}-journal" ] && cp "${backup_file}-journal" "${SMS_DB}-journal" + + # Fix ownership - telephony db is owned by radio + local radio_uid=$(stat -c '%u' /data/data/${TELEPHONY_PKG}/ 2>/dev/null || echo "1001") + local radio_gid=$(stat -c '%g' /data/data/${TELEPHONY_PKG}/ 2>/dev/null || echo "1001") + chown "${radio_uid}:${radio_gid}" "$SMS_DB" "${SMS_DB}-wal" "${SMS_DB}-journal" 2>/dev/null + chmod 660 "$SMS_DB" "${SMS_DB}-wal" "${SMS_DB}-journal" 2>/dev/null + restorecon "$SMS_DB" "${SMS_DB}-wal" "${SMS_DB}-journal" 2>/dev/null + + log "SMS database restored from ${backup_file}" + log "Restart Messages app or reboot for changes to take effect" + echo "RESTORED=${backup_file}" + return 0 +} + +cmd_restore_rcs() { + local backup_file="$1" + if [ -z "$backup_file" ]; then + backup_file=$(ls -t "${BACKUP_DIR}/rcs"/*.db 2>/dev/null | head -1) + fi + + if [ -z "$backup_file" ] || [ ! -f "$backup_file" ]; then + err "No RCS backup found" + return 1 + fi + + am force-stop "$MSG_PKG" 2>/dev/null + + cp "$backup_file" "$RCS_DB" + [ -f "${backup_file}-wal" ] && cp "${backup_file}-wal" "${RCS_DB}-wal" + [ -f "${backup_file}-journal" ] && cp "${backup_file}-journal" "${RCS_DB}-journal" + + # Fix ownership to match Messages app uid + local msg_uid=$(stat -c '%u' "/data/data/${MSG_PKG}/" 2>/dev/null) + local msg_gid=$(stat -c '%g' "/data/data/${MSG_PKG}/" 2>/dev/null) + if [ -n "$msg_uid" ]; then + chown "${msg_uid}:${msg_gid}" "$RCS_DB" "${RCS_DB}-wal" "${RCS_DB}-journal" 2>/dev/null + chmod 660 "$RCS_DB" "${RCS_DB}-wal" "${RCS_DB}-journal" 2>/dev/null + restorecon "$RCS_DB" "${RCS_DB}-wal" "${RCS_DB}-journal" 2>/dev/null + fi + + log "RCS database restored from ${backup_file}" + echo "RESTORED=${backup_file}" + return 0 +} + +cmd_list_backups() { + local type="$1" + case "$type" in + sms) + ls -1t "${BACKUP_DIR}/sms"/*.db 2>/dev/null | while read f; do + local size=$(du -h "$f" | cut -f1) + local name=$(basename "$f") + echo "${f}|${name}|${size}" + done + ;; + rcs) + ls -1t "${BACKUP_DIR}/rcs"/*.db 2>/dev/null | while read f; do + local size=$(du -h "$f" | cut -f1) + local name=$(basename "$f") + echo "${f}|${name}|${size}" + done + ;; + attachments) + ls -1dt "${BACKUP_DIR}/attachments"/*/ 2>/dev/null | while read d; do + local size=$(du -sh "$d" 2>/dev/null | cut -f1) + local count=$(find "$d" -type f 2>/dev/null | wc -l) + local name=$(basename "$d") + echo "${d}|${name}|${size}|${count} files" + done + ;; + esac +} + +cmd_delete_backup() { + local path="$1" + # Safety: only allow deleting from our backup directory + case "$path" in + ${BACKUP_DIR}/*) + if [ -f "$path" ]; then + rm -f "$path" "${path}-wal" "${path}-journal" + log "Deleted backup: ${path}" + elif [ -d "$path" ]; then + rm -rf "$path" + log "Deleted backup directory: ${path}" + else + err "Backup not found: ${path}" + return 1 + fi + ;; + *) + err "Refusing to delete outside backup directory: ${path}" + return 1 + ;; + esac +} + +cmd_apply_mod() { + log "Starting Messages Mod+ apply..." + + # Verify package exists + if ! pm list packages | grep -q "$MSG_PKG"; then + err "Google Messages not installed" + return 1 + fi + + # Check if already modded + if is_updated_system_app; then + log "Messages is already running as user-space updated system app" + echo "ALREADY_MODDED=true" + return 0 + fi + + # Step 1: Get current APK paths before disabling + log "Collecting APK paths..." + local apk_paths=$(get_apk_paths) + if [ -z "$apk_paths" ]; then + err "Could not find Messages APK paths" + return 1 + fi + + # Step 2: Save APKs to backup + ensure_backup_dir + local apk_dir="${BACKUP_DIR}/apks" + rm -f "${apk_dir}"/*.apk 2>/dev/null + + local apk_count=0 + local apk_list="" + echo "$apk_paths" | while read apk_path; do + if [ -f "$apk_path" ]; then + local apk_name=$(basename "$apk_path") + cp "$apk_path" "${apk_dir}/${apk_name}" + log "Saved: ${apk_name}" + fi + done + + # Build the install command from saved APKs + apk_list=$(ls -1 "${apk_dir}"/*.apk 2>/dev/null | tr '\n' ' ') + if [ -z "$apk_list" ]; then + err "No APKs were saved, aborting" + return 1 + fi + + apk_count=$(ls -1 "${apk_dir}"/*.apk 2>/dev/null | wc -l) + log "Saved ${apk_count} APK split(s)" + + # Step 3: Disable the system app + log "Disabling system Messages..." + pm disable-user --user 0 "$MSG_PKG" 2>&1 + + # Step 4: Reinstall as user-space app + log "Installing as user-space app..." + local install_result + # pm install requires -t for test and --bypass-low-target-sdk-block on newer Android + # Use session-based install for split APKs + local session_id=$(pm install-create 2>&1 | grep -oE '[0-9]+') + + if [ -z "$session_id" ]; then + err "Failed to create install session" + pm enable "$MSG_PKG" 2>/dev/null + return 1 + fi + + local idx=0 + for apk in ${apk_dir}/*.apk; do + local apk_size=$(stat -c '%s' "$apk" 2>/dev/null || wc -c < "$apk") + local apk_name=$(basename "$apk") + pm install-write -S "$apk_size" "$session_id" "$apk_name" "$apk" 2>&1 + idx=$((idx + 1)) + done + + install_result=$(pm install-commit "$session_id" 2>&1) + + if echo "$install_result" | grep -qi "success"; then + log "Installation successful" + else + # Fallback: try direct install + log "Session install returned: ${install_result}, trying direct method..." + local apk_args="" + for apk in ${apk_dir}/*.apk; do + apk_args="${apk_args} ${apk}" + done + install_result=$(pm install $apk_args 2>&1) + if ! echo "$install_result" | grep -qi "success"; then + err "Installation failed: ${install_result}" + pm enable "$MSG_PKG" 2>/dev/null + return 1 + fi + fi + + # Step 5: Re-enable + log "Re-enabling package..." + pm enable "$MSG_PKG" 2>&1 + + # Step 6: Verify + if is_updated_system_app; then + log "Messages Mod+ applied successfully!" + log "Messages is now running as a user-space app" + echo "RESULT=success" + return 0 + else + err "Mod may not have applied correctly - check package state" + echo "RESULT=uncertain" + return 1 + fi +} + +cmd_uninstall() { + log "Reverting Messages to stock system app..." + + if ! pm list packages | grep -q "$MSG_PKG"; then + err "Google Messages not installed" + return 1 + fi + + if ! is_updated_system_app; then + log "Messages is already running as stock system app" + echo "ALREADY_STOCK=true" + return 0 + fi + + # Uninstall updates reverts to the system version + log "Removing user-space updates..." + pm uninstall-updates "$MSG_PKG" 2>&1 || { + # Alternative method + pm install-existing "$MSG_PKG" 2>/dev/null + cmd install -r --user 0 "$MSG_PKG" 2>/dev/null + } + + # Make sure it's enabled + pm enable "$MSG_PKG" 2>/dev/null + + if ! is_updated_system_app; then + log "Successfully reverted to stock system Messages" + echo "RESULT=success" + return 0 + else + err "Revert may not have completed - check package state" + echo "RESULT=uncertain" + return 1 + fi +} + +# Command router +case "$1" in + status) cmd_status ;; + backup-sms) cmd_backup_sms ;; + backup-rcs) cmd_backup_rcs ;; + backup-attach) cmd_backup_attachments ;; + restore-sms) cmd_restore_sms "$2" ;; + restore-rcs) cmd_restore_rcs "$2" ;; + list-backups) cmd_list_backups "$2" ;; + delete-backup) cmd_delete_backup "$2" ;; + apply) cmd_apply_mod ;; + uninstall) cmd_uninstall ;; + *) + echo "Messages Mod+ v1.0.0" + echo "" + echo "Usage: $0 [args]" + echo "" + echo "Commands:" + echo " status Show current Messages state" + echo " apply Apply mod (reinstall as user-space app)" + echo " uninstall Revert to stock system app" + echo " backup-sms Backup SMS/MMS database" + echo " backup-rcs Backup RCS database" + echo " backup-attach Backup message attachments" + echo " restore-sms [f] Restore SMS/MMS database (latest or specific file)" + echo " restore-rcs [f] Restore RCS database (latest or specific file)" + echo " list-backups List backups (sms|rcs|attachments)" + echo " delete-backup

Delete a backup file or directory" + echo "" + exit 1 + ;; +esac diff --git a/uninstall.sh b/uninstall.sh new file mode 100755 index 0000000..e6e479e --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,15 @@ +#!/system/bin/sh +# Messages Mod+ - Module Uninstall Hook +# Reverts Messages to stock when the module is removed from KernelSU + +MSG_PKG="com.google.android.apps.messaging" + +# Check if Messages is in the updated state and revert +if dumpsys package "$MSG_PKG" | grep "pkgFlags" | head -1 | grep -q "UPDATED_SYSTEM_APP"; then + echo "[MessagesModPlus] Reverting Messages to stock system app..." + pm uninstall-updates "$MSG_PKG" 2>/dev/null + pm enable "$MSG_PKG" 2>/dev/null + echo "[MessagesModPlus] Messages reverted to stock" +fi + +echo "[MessagesModPlus] Module uninstalled. Backups remain at /sdcard/MessagesModPlus/" diff --git a/webroot/index.html b/webroot/index.html new file mode 100644 index 0000000..ebbe932 --- /dev/null +++ b/webroot/index.html @@ -0,0 +1,713 @@ + + + + + +Messages Mod+ + + + + +

+

Messages Mod+

+

Fix RCS on rooted devices

+
+ + +
+
+ Messages State + Checking... +
+
+ Package + -- +
+
+ Backups + -- +
+
+ + + + + +
+ + +
+
Backup
+
+ + + +
+
+ + +
+
Restore
+
+ + +
+
+ + +
+
Danger Zone
+ +
+ + + + + + +