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
- Incorrect Path Format: Using simplified paths that don't match real Android APK installation structure
- Missing Hash Directories: Not accounting for the
~~hash==directory structure - Missing Package Hashes: Not accounting for package-specific hash suffixes
- Limited Path Discovery: Only checking a few basic paths
- 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/appdirectory for hash directories - Search within hash directories for package directories
- Find
base.apkfiles 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
- Test on modern Android devices (Android 10+)
- Test on legacy devices (Android 9 and below)
- Monitor logcat for path discovery messages
- Test with different APK installation methods
- Verify hash-based path discovery works correctly
- 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
- Clean and rebuild the project in Android Studio
- Test app startup on the target device
- Monitor logcat for path discovery messages
- 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.