收集崩溃log的代码
package packagename.report;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteCantOpenDatabaseException;
import android.os.SystemClock;
import packagename.LauncherProvider;
import packagename.next.utils.ErrorReportUtils;
import packagename.timeline.TimelineUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Random;
import androidx.annotation.Keep;
/**
* @author SHBU
*/
public class SqlCantOpenCrashAnalyzer {
private static boolean chmodRetried = false;
/**
* a workaround for online crash: sql open exception
*
* @param context
*/
public static void uploadDatabaseFileInfoAndRetry(Context context, String dbName, SQLiteCantOpenDatabaseException sqlCantOpen) {
// collect file info
StringBuilder stringBuilder = new StringBuilder();
int retryTime = 0;
try {
String key = "retryTime";
SharedPreferences testSP = context.getSharedPreferences("sqlCrashTestSP", Context.MODE_PRIVATE);
retryTime = testSP.getInt(key, 0);
testSP.edit().putInt(key, ++retryTime).commit();
stringBuilder.append("\nretryTime:").append(retryTime);
} catch (Throwable e) {
e.printStackTrace();
stringBuilder.append("\nSPExpt:").append(e.getMessage()).append(",type:").append(e.getClass().getName());
}
if (retryTime > 8) {
android.os.Process.killProcess(android.os.Process.myPid());
return;
}
// abs path should be /data/user/0/packagename/databases/launcher.db
File databaseFile = context.getDatabasePath(dbName);
// abs path should be /data/user/0/packagename/files
File filesDir = context.getFilesDir();
// abs path should be /data/user/0/packagename/cache
File cacheDir = context.getCacheDir();
File eCacheDir = context.getExternalCacheDir();
File userDir = new File("/data/user");
// abs path should be /data/user/0/packagename/databases
File databaseDir = databaseFile.getParentFile();
// abs path should be /data/user/0/packagename
File homeDir = databaseDir.getParentFile();
// abs path should be /data/user/0/packagename
File homeDir1 = filesDir.getParentFile();
// runCommAndLog("getenforce", "getenforce", stringBuilder);// no permission for exec this command
logFileInfoAndTryChmodForDir(context, databaseFile, stringBuilder);
logFileInfoAndTryChmodForDir(context, databaseDir, stringBuilder);
logFileInfoAndTryChmodForDir(context, homeDir, stringBuilder);
logFileInfoAndTryChmodForDir(context, filesDir, stringBuilder);
if (!homeDir.getAbsolutePath().equals(homeDir1.getAbsolutePath())) {
logFileInfoAndTryChmodForDir(context, homeDir1, stringBuilder);
}
logFileInfoAndTryChmodForDir(context, cacheDir, stringBuilder);
logFileInfoAndTryChmodForDir(context, eCacheDir, stringBuilder);
boolean fileExist = databaseFile.exists();
boolean deleteSucc = false;
if (fileExist) {
boolean fileIsDirectory = databaseFile.isDirectory();
if (fileIsDirectory) {
boolean fileIsDirectoryDeletable = databaseFile.delete();
stringBuilder.append("\ndbFileDirectoryDeletable: ").append(fileIsDirectoryDeletable);
if (fileIsDirectoryDeletable) {
deleteSucc = true;
}
} else {
// try delete db file
try {
deleteSucc = databaseFile.delete();
stringBuilder.append("\ndbFileCanDelete: ").append(deleteSucc);
// if rename strategy once worked and try rename it to the original one
if (deleteSucc && !LauncherProvider.useNewDBName) {
File dbFile = context.getDatabasePath(LauncherProvider.DATABASE_NAME_NEW);
if (dbFile.exists()) {
boolean renameTo = dbFile.renameTo(context.getDatabasePath(LauncherProvider.DATABASE_NAME));
stringBuilder.append("\ndbFileCanRenameTo: ").append(renameTo);
}
}
} catch (Throwable e) {
stringBuilder.append("\ndbFileCanDelete: ").append("exception:").append(e.getClass().getName()).append("-").append(e.getMessage());
}
}
}
String timelineEnabled;
try {
boolean timelineOn = TimelineUtils.isTimelineEnabled(context);
if (timelineOn) {
timelineEnabled = "y";
} else {
timelineEnabled = "n";
}
} catch (Throwable e) {
timelineEnabled = "error:" + e.getMessage() + ", " + e.getClass().getName();
e.printStackTrace();
}
stringBuilder.append("\ntimelineOn").append(timelineEnabled);
String message = stringBuilder.append("\noriginal message: ").append(sqlCantOpen.getMessage()).toString();
logFileInfoAndTryChmodForDir(context, userDir, stringBuilder);
// already retried with new DB name, no need to retry
if (LauncherProvider.useNewDBName) {
onAllMethodFailed(context, sqlCantOpen, message);
return;
}
if (!deleteSucc) {
LauncherProvider.useNewDBName = true;
}
throw new RetryException(message);
}
public static void onAllMethodFailed(Context context, Throwable throwable, String message) {
Random random = new Random();
int i = random.nextInt(100);
RuntimeException runtimeException = new RuntimeException(message, throwable);
if (i == 0) {
throw runtimeException;
} else {
ErrorReportUtils.sendErrorEvent("All Failed!" + message, runtimeException);
// before suicide, sleep main thread to give sendError thread more time
SystemClock.sleep(3 * 1000);
// just kill launcher to avoid too many crash upload
android.os.Process.killProcess(android.os.Process.myPid());
}
}
private static void logFileInfoAndTryChmodForDir(Context context, File file, StringBuilder stringBuilder) {
if (file == null) {
stringBuilder.append("\nfileObj: ").append("null");
return;
}
long freeSpace = file.getFreeSpace();
long totalSpace = file.getTotalSpace();
long usableSpace = file.getUsableSpace();
stringBuilder.append("\nfilePath: ").append(file.getAbsolutePath());
stringBuilder.append("\npFUTSpace: ").append(freeSpace).append(",").append(usableSpace).append(",").append(totalSpace);
boolean fileExist = file.exists();
stringBuilder.append("\nfileExist: ").append(fileExist);
if (fileExist) {
stringBuilder.append("\nfileCanRead: ").append(file.canRead());
stringBuilder.append("\nfileCanWrite: ").append(file.canWrite());
stringBuilder.append("\nfileCanExecute: ").append(file.canExecute());
stringBuilder.append("\nfileLength: ").append(file.length());
boolean fileIsDirectory = file.isDirectory();
stringBuilder.append("\nfileIsDirectory: ").append(fileIsDirectory);
}
runCommAndLog("ls -Zl " + file.getAbsolutePath(), "ls", stringBuilder);
int exitCode = runCommAndLog("chmod -R 770 " + file.getAbsolutePath(), "chmod", stringBuilder);
// trigger retry
if (exitCode == 0 && !chmodRetried) {
chmodRetried = true;
throw new RetryException("chmod succ!" + stringBuilder.append("\nEnd.").toString());
} else {
runCommAndLog("restorecon -RF " + file.getAbsolutePath(), "restorecon", stringBuilder);
stringBuilder.append("\nchmodRetried: ").append(chmodRetried);
}
}
private static int runCommAndLog(String comm, String preffix, StringBuilder stringBuilder) {
java.lang.Process exec = null;
BufferedReader bufferedReader = null;
int exitCode = -1;
stringBuilder.append("\ncomm: ").append(comm);
try {
exec = Runtime.getRuntime().exec(comm);
exitCode = exec.waitFor();
if (exitCode == 0) {
bufferedReader = new BufferedReader(new InputStreamReader(exec.getInputStream()));
stringBuilder.append("\n").append(preffix).append("Output: ");
} else {
stringBuilder.append("\nerrorCode: ").append(exitCode);
bufferedReader = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
stringBuilder.append("\n").append(preffix).append("ErrorOutput: ");
}
String line = null;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append('\n');
}
stringBuilder.append(".");
} catch (Throwable ex) {
stringBuilder.append("\n").append(preffix).append("Exception: ").append(ex.getClass().getName()).append(":").append(ex.getMessage());
ex.printStackTrace();
} finally {
if (exec != null) {
exec.destroy();
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
return exitCode;
}
@Keep
public static class RetryException extends RuntimeException {
RetryException(String message) {
super(message);
}
RetryException(String message, Throwable e) {
super(message, e);
}
}
}
`