Loading core/java/android/provider/Settings.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -14908,6 +14908,17 @@ public final class Settings { @Readable @Readable public static final String DROPBOX_TAG_PREFIX = "dropbox:"; public static final String DROPBOX_TAG_PREFIX = "dropbox:"; /** * Lines of kernel logs to include with system crash/ANR/etc. reports, as a * prefix of the dropbox tag of the report type. For example, * "kernel_logs_for_system_server_anr" controls the lines of kernel logs * captured with system server ANR reports. 0 to disable. * * @hide */ @Readable public static final String ERROR_KERNEL_LOG_PREFIX = "kernel_logs_for_"; /** /** * Lines of logcat to include with system crash/ANR/etc. reports, as a * Lines of logcat to include with system crash/ANR/etc. reports, as a * prefix of the dropbox tag of the report type. For example, * prefix of the dropbox tag of the report type. For example, packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -233,6 +233,7 @@ public class SettingsBackupTest { Settings.Global.ENHANCED_4G_MODE_ENABLED, Settings.Global.ENHANCED_4G_MODE_ENABLED, Settings.Global.ENABLE_16K_PAGES, // Added for 16K developer option Settings.Global.ENABLE_16K_PAGES, // Added for 16K developer option Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES, Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES, Settings.Global.ERROR_KERNEL_LOG_PREFIX, Settings.Global.ERROR_LOGCAT_PREFIX, Settings.Global.ERROR_LOGCAT_PREFIX, Settings.Global.EUICC_PROVISIONED, Settings.Global.EUICC_PROVISIONED, Settings.Global.EUICC_SUPPORTED_COUNTRIES, Settings.Global.EUICC_SUPPORTED_COUNTRIES, Loading services/core/java/com/android/server/am/ActivityManagerService.java +125 −117 Original line number Original line Diff line number Diff line Loading @@ -598,6 +598,9 @@ public class ActivityManagerService extends IActivityManager.Stub // as one line, but close enough for now. // as one line, but close enough for now. static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100; static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100; // How many seconds should the system wait before terminating the spawned logcat process. static final int LOGCAT_TIMEOUT_SEC = 10; // Necessary ApplicationInfo flags to mark an app as persistent // Necessary ApplicationInfo flags to mark an app as persistent static final int PERSISTENT_MASK = static final int PERSISTENT_MASK = ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT; ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT; Loading Loading @@ -9939,8 +9942,7 @@ public class ActivityManagerService extends IActivityManager.Stub // If process is null, we are being called from some internal code // If process is null, we are being called from some internal code // and may be about to die -- run this synchronously. // and may be about to die -- run this synchronously. final boolean runSynchronously = process == null; final boolean runSynchronously = process == null; Thread worker = Thread worker = new Thread("Error dump: " + dropboxTag) { new Thread("Error dump: " + dropboxTag) { @Override @Override public void run() { public void run() { if (report != null) { if (report != null) { Loading @@ -9948,48 +9950,39 @@ public class ActivityManagerService extends IActivityManager.Stub } } String logcatSetting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag; String logcatSetting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag; String maxBytesSetting = String kerLogSetting = Settings.Global.ERROR_KERNEL_LOG_PREFIX + dropboxTag; Settings.Global.MAX_ERROR_BYTES_PREFIX + dropboxTag; String maxBytesSetting = Settings.Global.MAX_ERROR_BYTES_PREFIX + dropboxTag; int lines = int logcatLines = Build.IS_USER Build.IS_USER ? 0 ? 0 : Settings.Global.getInt( : Settings.Global.getInt(mContext.getContentResolver(), logcatSetting, 0); mContext.getContentResolver(), logcatSetting, 0); int kernelLogLines = Build.IS_USER int dropboxMaxSize = ? 0 Settings.Global.getInt( : Settings.Global.getInt(mContext.getContentResolver(), kerLogSetting, 0); mContext.getContentResolver(), int dropboxMaxSize = Settings.Global.getInt( maxBytesSetting, mContext.getContentResolver(), maxBytesSetting, DROPBOX_DEFAULT_MAX_SIZE); DROPBOX_DEFAULT_MAX_SIZE); if (dataFile != null) { if (dataFile != null) { // Attach the stack traces file to the report so collectors can load // Attach the stack traces file to the report so collectors can load them // them // by file if they have access. // by file if they have access. sb.append(DATA_FILE_PATH_HEADER) sb.append(DATA_FILE_PATH_HEADER) .append(dataFile.getAbsolutePath()) .append(dataFile.getAbsolutePath()).append('\n'); .append('\n'); int maxDataFileSize = int maxDataFileSize = dropboxMaxSize dropboxMaxSize - sb.length() - sb.length() - lines * RESERVED_BYTES_PER_LOGCAT_LINE - logcatLines * RESERVED_BYTES_PER_LOGCAT_LINE - kernelLogLines * RESERVED_BYTES_PER_LOGCAT_LINE - DATA_FILE_PATH_FOOTER.length(); - DATA_FILE_PATH_FOOTER.length(); if (maxDataFileSize > 0) { if (maxDataFileSize > 0) { // Inline dataFile contents if there is room. // Inline dataFile contents if there is room. try { try { sb.append( sb.append(FileUtils.readTextFile(dataFile, maxDataFileSize, FileUtils.readTextFile( dataFile, maxDataFileSize, "\n\n[[TRUNCATED]]\n")); "\n\n[[TRUNCATED]]\n")); } catch (IOException e) { } catch (IOException e) { Slog.e(TAG, "Error reading " + dataFile, e); Slog.e(TAG, "Error reading " + dataFile, e); } } } } // Always append the footer, even there wasn't enough space to inline the // Always append the footer, even there wasn't enough space to inline // the // dataFile contents. // dataFile contents. sb.append(DATA_FILE_PATH_FOOTER); sb.append(DATA_FILE_PATH_FOOTER); } } Loading @@ -9997,62 +9990,16 @@ public class ActivityManagerService extends IActivityManager.Stub if (crashInfo != null && crashInfo.stackTrace != null) { if (crashInfo != null && crashInfo.stackTrace != null) { sb.append(crashInfo.stackTrace); sb.append(crashInfo.stackTrace); } } boolean shouldAddLogs = logcatLines > 0 || kernelLogLines > 0; if (lines > 0 && !runSynchronously) { if (!runSynchronously && shouldAddLogs) { sb.append("\n"); sb.append("\n"); if (logcatLines > 0) { InputStreamReader input = null; fetchLogcatBuffers(sb, logcatLines, LOGCAT_TIMEOUT_SEC, try { List.of("events", "system", "main", "crash")); java.lang.Process logcat = new ProcessBuilder( // Time out after 10s of inactivity, but // kill logcat with SEGV // so we can investigate why it didn't // finish. "/system/bin/timeout", "-i", "-s", "SEGV", "10s", // Merge several logcat streams, and take // the last N lines. "/system/bin/logcat", "-v", "threadtime", "-b", "events", "-b", "system", "-b", "main", "-b", "crash", "-t", String.valueOf(lines)) .redirectErrorStream(true) .start(); try { logcat.getOutputStream().close(); } catch (IOException e) { } try { logcat.getErrorStream().close(); } catch (IOException e) { } input = new InputStreamReader(logcat.getInputStream()); int num; char[] buf = new char[8192]; while ((num = input.read(buf)) > 0) sb.append(buf, 0, num); } catch (IOException e) { Slog.e(TAG, "Error running logcat", e); } finally { if (input != null) try { input.close(); } catch (IOException e) { } } if (kernelLogLines > 0) { fetchLogcatBuffers(sb, kernelLogLines, LOGCAT_TIMEOUT_SEC / 2, List.of("kernel")); } } } } Loading Loading @@ -10320,6 +10267,67 @@ public class ActivityManagerService extends IActivityManager.Stub Binder.getCallingPid(), state); Binder.getCallingPid(), state); } } /** * Retrieves logs from specified logcat buffers and appends them to a StringBuilder * in the supplied order. The method executes a logcat command to fetch specific * log entries from the supplied buffers. * * @param sb the StringBuilder to append the logcat output to. * @param lines the number of lines to retrieve. * @param timeout the maximum allowed time in seconds for logcat to run before being terminated. * @param buffers the list of log buffers from which to retrieve logs. */ private static void fetchLogcatBuffers(StringBuilder sb, int lines, int timeout, List<String> buffers) { if (buffers.size() == 0 || lines <= 0 || timeout <= 0) { return; } List<String> command = new ArrayList<>(10 + (2 * buffers.size())); // Time out after 10s of inactivity, but kill logcat with SEGV // so we can investigate why it didn't finish. command.add("/system/bin/timeout"); command.add("-i"); command.add("-s"); command.add("SEGV"); command.add(timeout + "s"); // Merge several logcat streams, and take the last N lines. command.add("/system/bin/logcat"); command.add("-v"); // This adds a timestamp and thread info to each log line. command.add("threadtime"); for (String buffer : buffers) { command.add("-b"); command.add(buffer); } // Limit the output to the last N lines. command.add("-t"); command.add(String.valueOf(lines)); try { java.lang.Process proc = new ProcessBuilder(command).redirectErrorStream(true).start(); // Close the output stream immediately as we do not send input to the process. try { proc.getOutputStream().close(); } catch (IOException e) { } try (InputStreamReader reader = new InputStreamReader(proc.getInputStream())) { char[] buffer = new char[8192]; int numRead; while ((numRead = reader.read(buffer, 0, buffer.length)) > 0) { sb.append(buffer, 0, numRead); } } } catch (IOException e) { Slog.e(TAG, "Error running logcat", e); } } /** /** * Check if the calling process has the permission to dump given package, * Check if the calling process has the permission to dump given package, * throw SecurityException if it doesn't have the permission. * throw SecurityException if it doesn't have the permission. Loading Loading
core/java/android/provider/Settings.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -14908,6 +14908,17 @@ public final class Settings { @Readable @Readable public static final String DROPBOX_TAG_PREFIX = "dropbox:"; public static final String DROPBOX_TAG_PREFIX = "dropbox:"; /** * Lines of kernel logs to include with system crash/ANR/etc. reports, as a * prefix of the dropbox tag of the report type. For example, * "kernel_logs_for_system_server_anr" controls the lines of kernel logs * captured with system server ANR reports. 0 to disable. * * @hide */ @Readable public static final String ERROR_KERNEL_LOG_PREFIX = "kernel_logs_for_"; /** /** * Lines of logcat to include with system crash/ANR/etc. reports, as a * Lines of logcat to include with system crash/ANR/etc. reports, as a * prefix of the dropbox tag of the report type. For example, * prefix of the dropbox tag of the report type. For example,
packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -233,6 +233,7 @@ public class SettingsBackupTest { Settings.Global.ENHANCED_4G_MODE_ENABLED, Settings.Global.ENHANCED_4G_MODE_ENABLED, Settings.Global.ENABLE_16K_PAGES, // Added for 16K developer option Settings.Global.ENABLE_16K_PAGES, // Added for 16K developer option Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES, Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES, Settings.Global.ERROR_KERNEL_LOG_PREFIX, Settings.Global.ERROR_LOGCAT_PREFIX, Settings.Global.ERROR_LOGCAT_PREFIX, Settings.Global.EUICC_PROVISIONED, Settings.Global.EUICC_PROVISIONED, Settings.Global.EUICC_SUPPORTED_COUNTRIES, Settings.Global.EUICC_SUPPORTED_COUNTRIES, Loading
services/core/java/com/android/server/am/ActivityManagerService.java +125 −117 Original line number Original line Diff line number Diff line Loading @@ -598,6 +598,9 @@ public class ActivityManagerService extends IActivityManager.Stub // as one line, but close enough for now. // as one line, but close enough for now. static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100; static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100; // How many seconds should the system wait before terminating the spawned logcat process. static final int LOGCAT_TIMEOUT_SEC = 10; // Necessary ApplicationInfo flags to mark an app as persistent // Necessary ApplicationInfo flags to mark an app as persistent static final int PERSISTENT_MASK = static final int PERSISTENT_MASK = ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT; ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT; Loading Loading @@ -9939,8 +9942,7 @@ public class ActivityManagerService extends IActivityManager.Stub // If process is null, we are being called from some internal code // If process is null, we are being called from some internal code // and may be about to die -- run this synchronously. // and may be about to die -- run this synchronously. final boolean runSynchronously = process == null; final boolean runSynchronously = process == null; Thread worker = Thread worker = new Thread("Error dump: " + dropboxTag) { new Thread("Error dump: " + dropboxTag) { @Override @Override public void run() { public void run() { if (report != null) { if (report != null) { Loading @@ -9948,48 +9950,39 @@ public class ActivityManagerService extends IActivityManager.Stub } } String logcatSetting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag; String logcatSetting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag; String maxBytesSetting = String kerLogSetting = Settings.Global.ERROR_KERNEL_LOG_PREFIX + dropboxTag; Settings.Global.MAX_ERROR_BYTES_PREFIX + dropboxTag; String maxBytesSetting = Settings.Global.MAX_ERROR_BYTES_PREFIX + dropboxTag; int lines = int logcatLines = Build.IS_USER Build.IS_USER ? 0 ? 0 : Settings.Global.getInt( : Settings.Global.getInt(mContext.getContentResolver(), logcatSetting, 0); mContext.getContentResolver(), logcatSetting, 0); int kernelLogLines = Build.IS_USER int dropboxMaxSize = ? 0 Settings.Global.getInt( : Settings.Global.getInt(mContext.getContentResolver(), kerLogSetting, 0); mContext.getContentResolver(), int dropboxMaxSize = Settings.Global.getInt( maxBytesSetting, mContext.getContentResolver(), maxBytesSetting, DROPBOX_DEFAULT_MAX_SIZE); DROPBOX_DEFAULT_MAX_SIZE); if (dataFile != null) { if (dataFile != null) { // Attach the stack traces file to the report so collectors can load // Attach the stack traces file to the report so collectors can load them // them // by file if they have access. // by file if they have access. sb.append(DATA_FILE_PATH_HEADER) sb.append(DATA_FILE_PATH_HEADER) .append(dataFile.getAbsolutePath()) .append(dataFile.getAbsolutePath()).append('\n'); .append('\n'); int maxDataFileSize = int maxDataFileSize = dropboxMaxSize dropboxMaxSize - sb.length() - sb.length() - lines * RESERVED_BYTES_PER_LOGCAT_LINE - logcatLines * RESERVED_BYTES_PER_LOGCAT_LINE - kernelLogLines * RESERVED_BYTES_PER_LOGCAT_LINE - DATA_FILE_PATH_FOOTER.length(); - DATA_FILE_PATH_FOOTER.length(); if (maxDataFileSize > 0) { if (maxDataFileSize > 0) { // Inline dataFile contents if there is room. // Inline dataFile contents if there is room. try { try { sb.append( sb.append(FileUtils.readTextFile(dataFile, maxDataFileSize, FileUtils.readTextFile( dataFile, maxDataFileSize, "\n\n[[TRUNCATED]]\n")); "\n\n[[TRUNCATED]]\n")); } catch (IOException e) { } catch (IOException e) { Slog.e(TAG, "Error reading " + dataFile, e); Slog.e(TAG, "Error reading " + dataFile, e); } } } } // Always append the footer, even there wasn't enough space to inline the // Always append the footer, even there wasn't enough space to inline // the // dataFile contents. // dataFile contents. sb.append(DATA_FILE_PATH_FOOTER); sb.append(DATA_FILE_PATH_FOOTER); } } Loading @@ -9997,62 +9990,16 @@ public class ActivityManagerService extends IActivityManager.Stub if (crashInfo != null && crashInfo.stackTrace != null) { if (crashInfo != null && crashInfo.stackTrace != null) { sb.append(crashInfo.stackTrace); sb.append(crashInfo.stackTrace); } } boolean shouldAddLogs = logcatLines > 0 || kernelLogLines > 0; if (lines > 0 && !runSynchronously) { if (!runSynchronously && shouldAddLogs) { sb.append("\n"); sb.append("\n"); if (logcatLines > 0) { InputStreamReader input = null; fetchLogcatBuffers(sb, logcatLines, LOGCAT_TIMEOUT_SEC, try { List.of("events", "system", "main", "crash")); java.lang.Process logcat = new ProcessBuilder( // Time out after 10s of inactivity, but // kill logcat with SEGV // so we can investigate why it didn't // finish. "/system/bin/timeout", "-i", "-s", "SEGV", "10s", // Merge several logcat streams, and take // the last N lines. "/system/bin/logcat", "-v", "threadtime", "-b", "events", "-b", "system", "-b", "main", "-b", "crash", "-t", String.valueOf(lines)) .redirectErrorStream(true) .start(); try { logcat.getOutputStream().close(); } catch (IOException e) { } try { logcat.getErrorStream().close(); } catch (IOException e) { } input = new InputStreamReader(logcat.getInputStream()); int num; char[] buf = new char[8192]; while ((num = input.read(buf)) > 0) sb.append(buf, 0, num); } catch (IOException e) { Slog.e(TAG, "Error running logcat", e); } finally { if (input != null) try { input.close(); } catch (IOException e) { } } if (kernelLogLines > 0) { fetchLogcatBuffers(sb, kernelLogLines, LOGCAT_TIMEOUT_SEC / 2, List.of("kernel")); } } } } Loading Loading @@ -10320,6 +10267,67 @@ public class ActivityManagerService extends IActivityManager.Stub Binder.getCallingPid(), state); Binder.getCallingPid(), state); } } /** * Retrieves logs from specified logcat buffers and appends them to a StringBuilder * in the supplied order. The method executes a logcat command to fetch specific * log entries from the supplied buffers. * * @param sb the StringBuilder to append the logcat output to. * @param lines the number of lines to retrieve. * @param timeout the maximum allowed time in seconds for logcat to run before being terminated. * @param buffers the list of log buffers from which to retrieve logs. */ private static void fetchLogcatBuffers(StringBuilder sb, int lines, int timeout, List<String> buffers) { if (buffers.size() == 0 || lines <= 0 || timeout <= 0) { return; } List<String> command = new ArrayList<>(10 + (2 * buffers.size())); // Time out after 10s of inactivity, but kill logcat with SEGV // so we can investigate why it didn't finish. command.add("/system/bin/timeout"); command.add("-i"); command.add("-s"); command.add("SEGV"); command.add(timeout + "s"); // Merge several logcat streams, and take the last N lines. command.add("/system/bin/logcat"); command.add("-v"); // This adds a timestamp and thread info to each log line. command.add("threadtime"); for (String buffer : buffers) { command.add("-b"); command.add(buffer); } // Limit the output to the last N lines. command.add("-t"); command.add(String.valueOf(lines)); try { java.lang.Process proc = new ProcessBuilder(command).redirectErrorStream(true).start(); // Close the output stream immediately as we do not send input to the process. try { proc.getOutputStream().close(); } catch (IOException e) { } try (InputStreamReader reader = new InputStreamReader(proc.getInputStream())) { char[] buffer = new char[8192]; int numRead; while ((numRead = reader.read(buffer, 0, buffer.length)) > 0) { sb.append(buffer, 0, numRead); } } } catch (IOException e) { Slog.e(TAG, "Error running logcat", e); } } /** /** * Check if the calling process has the permission to dump given package, * Check if the calling process has the permission to dump given package, * throw SecurityException if it doesn't have the permission. * throw SecurityException if it doesn't have the permission. Loading