View Javadoc
1   package edu.jiangxin.apktoolbox.android.dumpsys.tojson;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.nio.file.Files;
6   import java.util.regex.Matcher;
7   import java.util.regex.Pattern;
8   
9   import org.apache.commons.lang3.StringUtils;
10  import org.json.JSONArray;
11  import org.json.JSONObject;
12  
13  public class Alarm2Json implements IDumpsys2Json {
14      @Override
15      public String dumpsys2Json(File file) {
16          String content;
17          try {
18              content = new String(Files.readAllBytes(file.toPath()));
19          } catch (IOException e) {
20              throw new RuntimeException("读取文件失败: " + file.getAbsolutePath(), e);
21          }
22          JSONObject result = new JSONObject();
23          parseSections(content, result);
24          return result.toString(2);
25      }
26  
27      private void parseSections(String content, JSONObject result) {
28          // 以两个换行分割各大段
29          String[] sections = content.split("\n\\s*\n");
30          for (String section : sections) {
31              String title = getSectionTitle(section);
32              if (title != null) {
33                  Object value = parseSectionContent(title, section);
34                  result.put(title, value);
35              } else if (section.trim().startsWith("nowRTC=")) {
36                  Object value = parseSectionContent("TimeInfo", section);
37                  result.put("TimeInfo", value);
38              }
39          }
40      }
41  
42      private String getSectionTitle(String section) {
43          Matcher m = Pattern.compile("^\\s*([\\w .-]+):", Pattern.MULTILINE).matcher(section);
44          if (m.find()) {
45              return m.group(1).trim();
46          }
47          return null;
48      }
49  
50      private Object parseSectionContent(String title, String section) {
51          if (title.equals("Settings") || title.equals("Feature Flags")) {
52              return parseKeyValueSection(section);
53          } else if (title.equals("Current AppStateTracker State")) {
54              return parseAppStateSection(section);
55          } else if (title.contains("pending alarms")) {
56              return parsePendingAlarms(section);
57          } else if (title.contains("TimeInfo")) {
58              return parseTimeInfoSection(section);
59          } else {
60              return section.trim();
61          }
62      }
63  
64      private JSONObject parseKeyValueSection(String section) {
65          JSONObject obj = new JSONObject();
66          Matcher m = Pattern.compile("^\\s*([\\w._-]+)=(.+)$", Pattern.MULTILINE).matcher(section);
67          while (m.find()) {
68              obj.put(m.group(1).trim(), m.group(2).trim());
69          }
70          return obj;
71      }
72  
73      private JSONObject parseAppStateSection(String section) {
74          JSONObject obj = new JSONObject();
75          Matcher m = Pattern.compile("^\\s*([\\w .-]+): (.+)$", Pattern.MULTILINE).matcher(section);
76          while (m.find()) {
77              String key = m.group(1).trim();
78              String value = m.group(2).trim();
79              if (value.startsWith("[") && value.endsWith("]")) {
80                  value = value.substring(1, value.length() - 1);
81                  JSONArray arr = new JSONArray();
82                  for (String v : value.split(", ?")) {
83                      if (!v.isEmpty()) arr.put(v.trim());
84                  }
85                  obj.put(key, arr);
86              } else {
87                  obj.put(key, value);
88              }
89          }
90          Matcher userMatcher = Pattern.compile("User (\\d+)\\n([\\s\\S]+?)(?=\\n\\s*\\w|$)").matcher(section);
91          while (userMatcher.find()) {
92              String userKey = "User " + userMatcher.group(1);
93              String pkgs = userMatcher.group(2);
94              JSONArray pkgArr = new JSONArray();
95              for (String line : pkgs.split("\n")) {
96                  line = line.trim();
97                  if (!line.isEmpty()) pkgArr.put(line);
98              }
99              obj.put(userKey, pkgArr);
100         }
101         return obj;
102     }
103 
104     private JSONArray parsePendingAlarms(String section) {
105         JSONArray alarms = new JSONArray();
106         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);
107         Matcher m = alarmStartPattern.matcher(section);
108         while (m.find()) {
109             JSONObject alarm = new JSONObject();
110             alarm.put("type", m.group(1));
111             alarm.put("number", m.group(2));
112             String details = m.group(3).trim();
113             String[] tmpArray = details.split("\\n", 2);
114             alarm.put("alarmInfo", tmpArray[0]);
115             details = details.replace(tmpArray[0], "");
116             Pattern fieldPattern = Pattern.compile(
117                     "tag=([^\n]+)|type=([^\\s]+)|origWhen=([^\\s]+)|window=([^\\s]+)|repeatInterval=([^\\s]+)|count=([^\\s]+)|flags=([^\\s]+)|operation=([^\n]+)|listener=([^\n]+)|idle-options=([^\n]+)",
118                     Pattern.MULTILINE);
119             Matcher fieldMatcher = fieldPattern.matcher(details);
120             while (fieldMatcher.find()) {
121                 if (fieldMatcher.group(1) != null) alarm.put("tag", fieldMatcher.group(1).trim());
122                 if (fieldMatcher.group(2) != null) alarm.put("alarmType", fieldMatcher.group(2).trim());
123                 if (fieldMatcher.group(3) != null) alarm.put("origWhen", fieldMatcher.group(3).trim());
124                 if (fieldMatcher.group(4) != null) alarm.put("window", fieldMatcher.group(4).trim());
125                 if (fieldMatcher.group(5) != null) alarm.put("repeatInterval", fieldMatcher.group(5).trim());
126                 if (fieldMatcher.group(6) != null) alarm.put("count", fieldMatcher.group(6).trim());
127                 if (fieldMatcher.group(7) != null) alarm.put("flags", fieldMatcher.group(7).trim());
128                 if (fieldMatcher.group(8) != null) alarm.put("operation", fieldMatcher.group(8).trim());
129                 if (fieldMatcher.group(9) != null) alarm.put("listener", fieldMatcher.group(9).trim());
130                 if (fieldMatcher.group(10) != null) alarm.put("idleOptions", fieldMatcher.group(10).trim());
131             }
132             Pattern extraPattern = Pattern.compile(
133                     "policyWhenElapsed: ([^\n]+)|whenElapsed=([^\\s]+)|maxWhenElapsed=([^\\s]+)|exactAllowReason=([^\\s]+)|procName ([^\\s]+)|PendingIntent\\{([^:]+): ([^}]+)\\}",
134                     Pattern.MULTILINE);
135             Matcher extraMatcher = extraPattern.matcher(details);
136             while (extraMatcher.find()) {
137                 if (extraMatcher.group(1) != null) alarm.put("policyWhenElapsed", extraMatcher.group(1).trim());
138                 if (extraMatcher.group(2) != null) alarm.put("whenElapsed", extraMatcher.group(2).trim());
139                 if (extraMatcher.group(3) != null) alarm.put("maxWhenElapsed", extraMatcher.group(3).trim());
140                 if (extraMatcher.group(4) != null) alarm.put("exactAllowReason", extraMatcher.group(4).trim());
141                 if (extraMatcher.group(5) != null) alarm.put("procName", extraMatcher.group(5).trim());
142                 if (extraMatcher.group(6) != null && extraMatcher.group(7) != null) {
143                     alarm.put("pendingIntent", extraMatcher.group(7).trim());
144                 }
145             }
146             alarm.put("rawDetails", details); // 保留原始内容
147             alarms.put(alarm);
148         }
149         return alarms;
150     }
151 
152     private JSONObject parseTimeInfoSection(String section) {
153         JSONObject obj = new JSONObject();
154 
155         String timeInformation = StringUtils.substringBetween(section, "nowRTC=", "mLastTimeChangeClockTime=").trim().replace(" ", "=");
156         String[] components = timeInformation.split("=");
157 
158         String dateTime = components[1] + " " + components[2];
159         Long uptimeMs = Long.valueOf(components[4]);
160 
161         long uptimeSeconds = uptimeMs / 1000;
162         long uptimeHours = uptimeSeconds / 3600;
163         long uptimeMinutes = uptimeSeconds % 3600 / 60;
164         long uptimeSecs = uptimeSeconds % 60;
165 
166         obj.put("System Uptime(ms)", uptimeMs);
167         obj.put("System Uptime", uptimeHours + ":" + uptimeMinutes + ":" + uptimeSecs);
168         obj.put("Last DateTime", dateTime);
169         return obj;
170     }
171 }