Alarm2Json.java
package edu.jiangxin.apktoolbox.android.dumpsys.tojson;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
public class Alarm2Json implements IDumpsys2Json {
@Override
public String dumpsys2Json(File file) {
String content;
try {
content = new String(Files.readAllBytes(file.toPath()));
} catch (IOException e) {
throw new RuntimeException("读取文件失败: " + file.getAbsolutePath(), e);
}
JSONObject result = new JSONObject();
parseSections(content, result);
return result.toString(2);
}
private void parseSections(String content, JSONObject result) {
// 以两个换行分割各大段
String[] sections = content.split("\n\\s*\n");
for (String section : sections) {
String title = getSectionTitle(section);
if (title != null) {
Object value = parseSectionContent(title, section);
result.put(title, value);
} else if (section.trim().startsWith("nowRTC=")) {
Object value = parseSectionContent("TimeInfo", section);
result.put("TimeInfo", value);
}
}
}
private String getSectionTitle(String section) {
Matcher m = Pattern.compile("^\\s*([\\w .-]+):", Pattern.MULTILINE).matcher(section);
if (m.find()) {
return m.group(1).trim();
}
return null;
}
private Object parseSectionContent(String title, String section) {
if (title.equals("Settings") || title.equals("Feature Flags")) {
return parseKeyValueSection(section);
} else if (title.equals("Current AppStateTracker State")) {
return parseAppStateSection(section);
} else if (title.contains("pending alarms")) {
return parsePendingAlarms(section);
} else if (title.contains("TimeInfo")) {
return parseTimeInfoSection(section);
} else {
return section.trim();
}
}
private JSONObject parseKeyValueSection(String section) {
JSONObject obj = new JSONObject();
Matcher m = Pattern.compile("^\\s*([\\w._-]+)=(.+)$", Pattern.MULTILINE).matcher(section);
while (m.find()) {
obj.put(m.group(1).trim(), m.group(2).trim());
}
return obj;
}
private JSONObject parseAppStateSection(String section) {
JSONObject obj = new JSONObject();
Matcher m = Pattern.compile("^\\s*([\\w .-]+): (.+)$", Pattern.MULTILINE).matcher(section);
while (m.find()) {
String key = m.group(1).trim();
String value = m.group(2).trim();
if (value.startsWith("[") && value.endsWith("]")) {
value = value.substring(1, value.length() - 1);
JSONArray arr = new JSONArray();
for (String v : value.split(", ?")) {
if (!v.isEmpty()) arr.put(v.trim());
}
obj.put(key, arr);
} else {
obj.put(key, value);
}
}
Matcher userMatcher = Pattern.compile("User (\\d+)\\n([\\s\\S]+?)(?=\\n\\s*\\w|$)").matcher(section);
while (userMatcher.find()) {
String userKey = "User " + userMatcher.group(1);
String pkgs = userMatcher.group(2);
JSONArray pkgArr = new JSONArray();
for (String line : pkgs.split("\n")) {
line = line.trim();
if (!line.isEmpty()) pkgArr.put(line);
}
obj.put(userKey, pkgArr);
}
return obj;
}
private JSONArray parsePendingAlarms(String section) {
JSONArray alarms = new JSONArray();
Pattern alarmStartPattern = Pattern.compile("^\s*(ELAPSED|ELAPSED_WAKEUP|RTC|RTC_WAKEUP) #(\\d+): (Alarm\\{.*?)(?=(^\\s*(ELAPSED|ELAPSED_WAKEUP|RTC|RTC_WAKEUP) #(\\d+):)|(\\s{2}))", Pattern.MULTILINE | Pattern.DOTALL);
Matcher m = alarmStartPattern.matcher(section);
while (m.find()) {
JSONObject alarm = new JSONObject();
alarm.put("type", m.group(1));
alarm.put("number", m.group(2));
String details = m.group(3).trim();
String[] tmpArray = details.split("\\n", 2);
alarm.put("alarmInfo", tmpArray[0]);
details = details.replace(tmpArray[0], "");
Pattern fieldPattern = Pattern.compile(
"tag=([^\n]+)|type=([^\\s]+)|origWhen=([^\\s]+)|window=([^\\s]+)|repeatInterval=([^\\s]+)|count=([^\\s]+)|flags=([^\\s]+)|operation=([^\n]+)|listener=([^\n]+)|idle-options=([^\n]+)",
Pattern.MULTILINE);
Matcher fieldMatcher = fieldPattern.matcher(details);
while (fieldMatcher.find()) {
if (fieldMatcher.group(1) != null) alarm.put("tag", fieldMatcher.group(1).trim());
if (fieldMatcher.group(2) != null) alarm.put("alarmType", fieldMatcher.group(2).trim());
if (fieldMatcher.group(3) != null) alarm.put("origWhen", fieldMatcher.group(3).trim());
if (fieldMatcher.group(4) != null) alarm.put("window", fieldMatcher.group(4).trim());
if (fieldMatcher.group(5) != null) alarm.put("repeatInterval", fieldMatcher.group(5).trim());
if (fieldMatcher.group(6) != null) alarm.put("count", fieldMatcher.group(6).trim());
if (fieldMatcher.group(7) != null) alarm.put("flags", fieldMatcher.group(7).trim());
if (fieldMatcher.group(8) != null) alarm.put("operation", fieldMatcher.group(8).trim());
if (fieldMatcher.group(9) != null) alarm.put("listener", fieldMatcher.group(9).trim());
if (fieldMatcher.group(10) != null) alarm.put("idleOptions", fieldMatcher.group(10).trim());
}
Pattern extraPattern = Pattern.compile(
"policyWhenElapsed: ([^\n]+)|whenElapsed=([^\\s]+)|maxWhenElapsed=([^\\s]+)|exactAllowReason=([^\\s]+)|procName ([^\\s]+)|PendingIntent\\{([^:]+): ([^}]+)\\}",
Pattern.MULTILINE);
Matcher extraMatcher = extraPattern.matcher(details);
while (extraMatcher.find()) {
if (extraMatcher.group(1) != null) alarm.put("policyWhenElapsed", extraMatcher.group(1).trim());
if (extraMatcher.group(2) != null) alarm.put("whenElapsed", extraMatcher.group(2).trim());
if (extraMatcher.group(3) != null) alarm.put("maxWhenElapsed", extraMatcher.group(3).trim());
if (extraMatcher.group(4) != null) alarm.put("exactAllowReason", extraMatcher.group(4).trim());
if (extraMatcher.group(5) != null) alarm.put("procName", extraMatcher.group(5).trim());
if (extraMatcher.group(6) != null && extraMatcher.group(7) != null) {
alarm.put("pendingIntent", extraMatcher.group(7).trim());
}
}
alarm.put("rawDetails", details); // 保留原始内容
alarms.put(alarm);
}
return alarms;
}
private JSONObject parseTimeInfoSection(String section) {
JSONObject obj = new JSONObject();
String timeInformation = StringUtils.substringBetween(section, "nowRTC=", "mLastTimeChangeClockTime=").trim().replace(" ", "=");
String[] components = timeInformation.split("=");
String dateTime = components[1] + " " + components[2];
Long uptimeMs = Long.valueOf(components[4]);
long uptimeSeconds = uptimeMs / 1000;
long uptimeHours = uptimeSeconds / 3600;
long uptimeMinutes = uptimeSeconds % 3600 / 60;
long uptimeSecs = uptimeSeconds % 60;
obj.put("System Uptime(ms)", uptimeMs);
obj.put("System Uptime", uptimeHours + ":" + uptimeMinutes + ":" + uptimeSecs);
obj.put("Last DateTime", dateTime);
return obj;
}
}