Files
NewBlackbox/REAL_WORLD_APK_PATH_FIX.md

8.5 KiB

Real-World APK Path Fix

Problem Analysis

The previous fallback paths were using simplified formats that don't match the actual APK installation structure on modern Android devices. The real APK paths use a complex hash-based directory structure:

Example Real Path:

/data/app/~~LqmY0IHlKQJtJ6Cih1C6jA==/com.linkedin.android-G8hAJLQTgTz1gJ0rAUxcqA==/base.apk

Previous Incorrect Paths:

/data/app/com.twitter.android-1/base.apk  ❌ (Doesn't exist)

Issues Identified

  1. Incorrect Path Format: Using simplified paths that don't match real Android APK installation structure
  2. Missing Hash Directories: Not accounting for the ~~hash== directory structure
  3. Missing Package Hashes: Not accounting for package-specific hash suffixes
  4. Limited Path Discovery: Only checking a few basic paths
  5. No Dynamic Discovery: Not searching through actual directory structures

Real-World APK Path Structure

Modern Android APK Installation Format

/data/app/~~{INSTALL_HASH}==/{PACKAGE_NAME}-{PACKAGE_HASH}==/base.apk

Components:

  • ~~{INSTALL_HASH}== - Installation session hash (e.g., ~~LqmY0IHlKQJtJ6Cih1C6jA==)
  • {PACKAGE_NAME}-{PACKAGE_HASH}== - Package name with unique hash (e.g., com.linkedin.android-G8hAJLQTgTz1gJ0rAUxcqA==)
  • base.apk - The actual APK file

Legacy Paths (Still Used)

/data/app/{PACKAGE_NAME}-{VERSION}/base.apk
/data/app/{PACKAGE_NAME}/base.apk

System Paths

/system/app/{PACKAGE_NAME}.apk
/system/priv-app/{PACKAGE_NAME}.apk
/system_ext/app/{PACKAGE_NAME}.apk
/product/app/{PACKAGE_NAME}.apk
/vendor/app/{PACKAGE_NAME}.apk

Fixes Implemented

1. Enhanced Path Discovery (BPackageManager.java)

Updated findActualApkPath method with real-world paths:

private String findActualApkPath(String packageName) {
    if (sIsFindingApkPath) {
        Log.w(TAG, "findActualApkPath called recursively, returning null to prevent infinite loop.");
        return null;
    }
    sIsFindingApkPath = true;
    try {
        // Skip PackageManager call to prevent infinite recursion
        Log.d(TAG, "Skipping PackageManager call to prevent recursion for " + packageName);
        
        // Try common paths including real-world hash-based paths
        String[] commonPaths = {
            // Real-world hash-based paths (most common)
            "/data/app/~~*/" + packageName + "-*/base.apk",
            "/data/app/~~*/" + packageName + "*/base.apk",
            
            // Legacy paths
            "/data/app/" + packageName + "-1/base.apk",
            "/data/app/" + packageName + "-2/base.apk",
            "/data/app/" + packageName + "/base.apk",
            
            // System paths
            "/system/app/" + packageName + ".apk",
            "/system/priv-app/" + packageName + ".apk",
            "/system_ext/app/" + packageName + ".apk",
            "/product/app/" + packageName + ".apk",
            "/vendor/app/" + packageName + ".apk"
        };
        
        // First try exact path matching
        for (String path : commonPaths) {
            if (isValidApkPath(path)) {
                Log.d(TAG, "Found existing APK at: " + path);
                return path;
            }
        }
        
        // If exact paths don't work, try to find hash-based paths dynamically
        String hashBasedPath = findHashBasedApkPath(packageName);
        if (hashBasedPath != null) {
            Log.d(TAG, "Found hash-based APK at: " + hashBasedPath);
            return hashBasedPath;
        }
        
        Log.w(TAG, "No existing APK found for " + packageName + ", using null path");
        return null;
    } finally {
        sIsFindingApkPath = false; // Reset flag
    }
}

2. Dynamic Hash-Based Path Discovery (BPackageManager.java)

Added findHashBasedApkPath method for real-world path discovery:

private String findHashBasedApkPath(String packageName) {
    try {
        File dataAppDir = new File("/data/app");
        if (!dataAppDir.exists() || !dataAppDir.isDirectory()) {
            return null;
        }
        
        // Look for hash directories (~~hash==)
        File[] hashDirs = dataAppDir.listFiles((dir, name) -> name.startsWith("~~") && name.endsWith("=="));
        if (hashDirs == null) {
            return null;
        }
        
        for (File hashDir : hashDirs) {
            if (!hashDir.isDirectory()) {
                continue;
            }
            
            // Look for package directories within hash directories
            File[] packageDirs = hashDir.listFiles((dir, name) -> name.startsWith(packageName));
            if (packageDirs == null) {
                continue;
            }
            
            for (File packageDir : packageDirs) {
                if (!packageDir.isDirectory()) {
                    continue;
                }
                
                // Look for base.apk within package directory
                File baseApk = new File(packageDir, "base.apk");
                if (isValidApkPath(baseApk.getAbsolutePath())) {
                    return baseApk.getAbsolutePath();
                }
            }
        }
    } catch (Exception e) {
        Log.d(TAG, "Error searching for hash-based APK path for " + packageName + ": " + e.getMessage());
    }
    
    return null;
}

3. Enhanced Path Validation (BPackageManager.java)

Updated isValidApkPath to handle wildcard patterns:

private boolean isValidApkPath(String path) {
    try {
        // Skip wildcard patterns - they need to be resolved first
        if (path.contains("*")) {
            return false;
        }
        
        File apkFile = new File(path);
        if (!apkFile.exists()) {
            return false;
        }
        
        // Additional validation: check if it's readable and has reasonable size
        if (!apkFile.canRead()) {
            Log.d(TAG, "APK file not readable: " + path);
            return false;
        }
        
        long fileSize = apkFile.length();
        if (fileSize < 1024) { // Less than 1KB is probably not a valid APK
            Log.d(TAG, "APK file too small: " + path + " (size: " + fileSize + ")");
            return false;
        }
        
        return true;
    } catch (Exception e) {
        Log.d(TAG, "Error checking APK path " + path + ": " + e.getMessage());
        return false;
    }
}

Key Changes Made

1. Real-World Path Patterns

  • Added hash-based directory patterns (~~hash==)
  • Added package hash patterns (package-hash==)
  • Included all system partition paths
  • Added legacy path support

2. Dynamic Path Discovery

  • Scan /data/app directory for hash directories
  • Search within hash directories for package directories
  • Find base.apk files within package directories
  • Handle multiple installation sessions

3. Enhanced Validation

  • Skip wildcard patterns that need resolution
  • Validate file existence, readability, and size
  • Comprehensive error handling
  • Detailed logging for debugging

4. Comprehensive Path Coverage

  • Modern hash-based paths (most common)
  • Legacy version-based paths
  • All system partition paths
  • Dynamic discovery for unknown patterns

Expected Results

After implementing these fixes, the app should:

Find real APK paths using hash-based directory structure
Handle modern Android installations correctly
Support legacy installations for older devices
Discover APKs dynamically when exact paths are unknown
Validate APK files before using them
Provide detailed logging for path discovery

Testing Recommendations

  1. Test on modern Android devices (Android 10+)
  2. Test on legacy devices (Android 9 and below)
  3. Monitor logcat for path discovery messages
  4. Test with different APK installation methods
  5. Verify hash-based path discovery works correctly
  6. Test with system apps in different partitions

Additional Notes

  • The fix supports both modern and legacy APK installation formats
  • Dynamic discovery handles unknown hash patterns
  • Enhanced validation prevents using invalid APK files
  • Comprehensive logging helps with debugging path issues
  • The solution is backward compatible with older Android versions

Build Instructions

  1. Clean and rebuild the project in Android Studio
  2. Test app startup on the target device
  3. Monitor logcat for path discovery messages
  4. Verify that real APK paths are found correctly

The comprehensive real-world APK path discovery implemented should resolve the path issues and allow the app to find actual APK files on modern Android devices.