View Javadoc
1   package edu.jiangxin.apktoolbox.android.dumpsys.alarm;
2   
3   import edu.jiangxin.apktoolbox.file.core.EncoderDetector;
4   import edu.jiangxin.apktoolbox.swing.extend.EasyPanel;
5   import edu.jiangxin.apktoolbox.swing.treetable.MyAbstractTreeTableModel;
6   import edu.jiangxin.apktoolbox.swing.treetable.MyTreeTable;
7   import edu.jiangxin.apktoolbox.utils.Constants;
8   import org.apache.commons.exec.CommandLine;
9   import org.apache.commons.exec.DefaultExecutor;
10  import org.apache.commons.exec.PumpStreamHandler;
11  import org.apache.commons.io.FileUtils;
12  import org.apache.commons.lang3.StringUtils;
13  
14  import javax.swing.*;
15  import java.awt.*;
16  import java.awt.event.ActionEvent;
17  import java.awt.event.ActionListener;
18  import java.io.ByteArrayOutputStream;
19  import java.io.File;
20  import java.io.IOException;
21  import java.nio.charset.Charset;
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  public class DumpsysAlarmPanel extends EasyPanel {
26  
27      private JPanel operationPanel;
28  
29      private JPanel lastDateTimePanel;
30  
31      private JTextField lastDateTimeField;
32  
33      private JPanel systemUptime1Panel;
34  
35      private JTextField systemUptime1Field;
36  
37      private JPanel systemUptime2Panel;
38  
39      private JTextField systemUptime2Field;
40  
41      private JPanel packagePanel;
42  
43      private JTextField packageField;
44  
45      private JTabbedPane tabbedPane;
46  
47      private JPanel tabularFormTabPanel;
48  
49      private JPanel rawSourceTabPanel;
50  
51      private JEditorPane editorPane;
52  
53      private List<AlarmTreeTableDataNode> children;
54  
55      private String alarmInfoString;
56  
57      private boolean alarmInfoValid;
58  
59      public DumpsysAlarmPanel() throws HeadlessException {
60          super();
61      }
62  
63      @Override
64      public void initUI() {
65          BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
66          setLayout(boxLayout);
67  
68          createOptionPanel();
69          add(operationPanel);
70          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
71  
72          createLastDateTimePanel();
73          add(lastDateTimePanel);
74          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
75  
76          createSystemUptime1Panel();
77          add(systemUptime1Panel);
78          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
79  
80          createSystemUptime2Panel();
81          add(systemUptime2Panel);
82          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
83  
84          createPackagePanel();
85          add(packagePanel);
86          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
87  
88          createTabbedPane();
89          add(tabbedPane);
90      }
91  
92      private void createOptionPanel() {
93          operationPanel = new JPanel();
94          operationPanel.setLayout(new BoxLayout(operationPanel, BoxLayout.X_AXIS));
95  
96          JButton loadFromDeviceButton = new JButton("Load From Device");
97          loadFromDeviceButton.addActionListener(new LoadFromDeviceButtonActionListener());
98  
99          JButton loadFromFileButton = new JButton("Load From File");
100         loadFromFileButton.addActionListener(new LoadFromFileButtonActionListener());
101 
102         operationPanel.add(loadFromDeviceButton);
103         operationPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
104         operationPanel.add(loadFromFileButton);
105         operationPanel.add(Box.createHorizontalGlue());
106     }
107 
108     private void createLastDateTimePanel() {
109         lastDateTimePanel = new JPanel();
110         lastDateTimePanel.setLayout(new BoxLayout(lastDateTimePanel, BoxLayout.X_AXIS));
111 
112         JLabel lastDateTimeLabel = new JLabel("Last DateTime");
113 
114         lastDateTimeField = new JTextField();
115 
116         lastDateTimePanel.add(lastDateTimeLabel);
117         lastDateTimePanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
118         lastDateTimePanel.add(lastDateTimeField);
119     }
120 
121     private void createSystemUptime1Panel() {
122         systemUptime1Panel = new JPanel();
123         systemUptime1Panel.setLayout(new BoxLayout(systemUptime1Panel, BoxLayout.X_AXIS));
124 
125         JLabel systemUptime1Label = new JLabel("System Uptime(ms)");
126 
127         systemUptime1Field = new JTextField();
128 
129         systemUptime1Panel.add(systemUptime1Label);
130         systemUptime1Panel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
131         systemUptime1Panel.add(systemUptime1Field);
132     }
133 
134     private void createSystemUptime2Panel() {
135         systemUptime2Panel = new JPanel();
136         systemUptime2Panel.setLayout(new BoxLayout(systemUptime2Panel, BoxLayout.X_AXIS));
137 
138         JLabel systemUptime2Label = new JLabel("System Uptime");
139 
140         systemUptime2Field = new JTextField();
141 
142         systemUptime2Panel.add(systemUptime2Label);
143         systemUptime2Panel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
144         systemUptime2Panel.add(systemUptime2Field);
145     }
146 
147     private void createPackagePanel() {
148         packagePanel = new JPanel();
149         packagePanel.setLayout(new BoxLayout(packagePanel, BoxLayout.X_AXIS));
150 
151         JLabel packageLabel = new JLabel("Package");
152 
153         packageField = new JTextField();
154 
155         packagePanel.add(packageLabel);
156         packagePanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
157         packagePanel.add(packageField);
158     }
159 
160     private void createTabbedPane() {
161         tabbedPane = new JTabbedPane();
162 
163         tabularFormTabPanel = new JPanel();
164         createTable();
165         tabbedPane.addTab("Tabular Form", null, tabularFormTabPanel, "Tabular Form");
166 
167         rawSourceTabPanel = new JPanel();
168         createRawSource();
169         tabbedPane.addTab("Raw source", null, rawSourceTabPanel, "Raw source");
170     }
171 
172     private void createTable() {
173         children = new ArrayList<>();
174         AlarmTreeTableDataNode root = new AlarmTreeTableDataNode("Root", "", "", "", "", children);
175         MyAbstractTreeTableModel treeTableModel = new AlarmTreeTableDataModel(root);
176         MyTreeTable myTreeTable = new MyTreeTable(treeTableModel);
177         JScrollPane scrollPane = new JScrollPane(myTreeTable);
178         scrollPane.setPreferredSize(new Dimension(Constants.DEFAULT_SCROLL_PANEL_WIDTH, Constants.DEFAULT_SCROLL_PANEL_HEIGHT));
179         tabularFormTabPanel.add(scrollPane);
180     }
181 
182     private void createRawSource() {
183         editorPane = new JEditorPane("text/plain", "");
184         editorPane.setEditable(false);
185         JScrollPane scrollPane = new JScrollPane(editorPane);
186         scrollPane.setPreferredSize(new Dimension(Constants.DEFAULT_SCROLL_PANEL_WIDTH, Constants.DEFAULT_SCROLL_PANEL_HEIGHT));
187         rawSourceTabPanel.add(scrollPane);
188     }
189 
190     private void getAlarmInfoStringFromDevice() {
191         final String cmd = "adb shell dumpsys alarm";
192         logger.info(cmd);
193         try (ByteArrayOutputStream outStream = new ByteArrayOutputStream();
194              ByteArrayOutputStream errStream = new ByteArrayOutputStream()
195         ) {
196             CommandLine commandLine = CommandLine.parse(cmd);
197             DefaultExecutor exec = new DefaultExecutor();
198             PumpStreamHandler streamHandler = new PumpStreamHandler(outStream, errStream);
199             exec.setStreamHandler(streamHandler);
200             int exitValue = exec.execute(commandLine);
201             logger.info("exitValue: [" + exitValue + "]");
202 
203             alarmInfoString = outStream.toString("UTF-8");
204             alarmInfoValid = !StringUtils.isEmpty(alarmInfoString);
205             if (!alarmInfoValid) {
206                 alarmInfoString = errStream.toString("UTF-8");
207             }
208         } catch (IOException ioe) {
209             logger.error("exec fail", ioe.getMessage());
210         }
211     }
212 
213     private void getAlarmInfoStringFromFile() {
214         JFileChooser jfc = new JFileChooser();
215         jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
216         jfc.setDialogTitle("Select a dumpsys alarm file");
217         int ret = jfc.showDialog(new JLabel(), null);
218         File file = jfc.getSelectedFile();
219         switch (ret) {
220             case JFileChooser.APPROVE_OPTION:
221                 try {
222                     alarmInfoString = FileUtils.readFileToString(file, Charset.forName(EncoderDetector.judgeFile(file.getCanonicalPath())));
223                     alarmInfoValid = true;
224                 } catch (IOException ex) {
225                     logger.error("readFileToString failed", ex);
226                     alarmInfoValid = false;
227                 }
228                 break;
229             default:
230                 break;
231         }
232     }
233 
234     private void updateUIFromString() {
235         alarmInfoString = StringUtils.isEmpty(alarmInfoString) ? "" : alarmInfoString;
236         editorPane.setText(alarmInfoString);
237 
238         if (!alarmInfoValid) {
239             children.clear();
240             return;
241         }
242 
243         String tmpInputString = alarmInfoString;
244 
245         String timeInformation = StringUtils.substringBetween(alarmInfoString, "nowRTC=", "mLastTimeChangeClockTime=").trim().replace(" ", "=");
246         String[] components = timeInformation.split("=");
247 
248         SharedData sharedData = SharedData.getInstance();
249         sharedData.setTimestamp(Long.valueOf(components[0]));
250         sharedData.setDateTime(components[1] + " " + components[2]);
251         sharedData.setUptimeMs(Long.valueOf(components[4]));
252 
253         long uptimeSeconds = sharedData.getUptimeMs() / 1000;
254         long uptimeHours = uptimeSeconds / 3600;
255         long uptimeMinutes = (uptimeSeconds % 3600) / 60;
256         long uptimeSecs = uptimeSeconds % 60;
257 
258         systemUptime1Field.setText(String.valueOf(sharedData.getUptimeMs()));
259         systemUptime2Field.setText(uptimeHours + ":" + uptimeMinutes + ":" + uptimeSecs);
260         lastDateTimeField.setText(sharedData.getDateTime());
261 
262         String pendingAlarmBatchesCountStr = StringUtils.substringBetween(tmpInputString, "Pending alarm batches: ", System.getProperty("line.separator"));
263         int pendingAlarmBatches = Integer.valueOf(pendingAlarmBatchesCountStr);
264         tmpInputString = StringUtils.substringAfter(tmpInputString, "Pending alarm batches: ");
265 
266         List<AlarmBatch> listBatches = new ArrayList<>();
267         while (true) {
268             String batchDefinition = StringUtils.substringBetween(tmpInputString, "Batch{", "}:" + System.getProperty("line.separator"));
269             if (StringUtils.isEmpty(batchDefinition)) {
270                 break;
271             }
272             AlarmBatch alarmBatch = AlarmBatch.fromString(batchDefinition);
273             if (alarmBatch == null) {
274                 break;
275             }
276             String alarmListDefinition = StringUtils.substringBetween(tmpInputString, "}:" + System.getProperty("line.separator"), "Batch{");
277             alarmListDefinition.replace("ELAPSED_WAKEUP", "ELAPSED").replace("RTC_WAKEUP", "ELAPSED").replace("RTC", "ELAPSED");
278             String[] alarmListTmp = alarmListDefinition.split("ELAPSED");
279             List<String> alarmList = new ArrayList<>();
280             for (int i = 0; i < alarmListTmp.length; i++) {
281                 if (StringUtils.isNotEmpty(alarmListTmp[i]) && StringUtils.isNotBlank(alarmListTmp[i])) {
282                     alarmList.add(alarmListTmp[i]);
283                 }
284             }
285 
286             for (int i = 0; i < alarmList.size(); ++i) {
287                 Alarm alarm = Alarm.fromString(alarmList.get(i));
288                 if (StringUtils.isNotEmpty(packageField.getText()) && StringUtils.equals(alarm.getOwnerPackageName(), packageField.getText())) {
289                     continue;
290                 }
291                 alarmBatch.appendAlarm(alarm);
292             }
293 
294             listBatches.add(alarmBatch);
295             if (listBatches.size() == pendingAlarmBatches) {
296                 break;
297             }
298 
299             tmpInputString = StringUtils.substringAfter(tmpInputString, "Batch{");
300         }
301         children.clear();
302         children.addAll(alarmBatches2AlarmTreeTableDataNodeList(listBatches));
303     }
304 
305     private List<AlarmTreeTableDataNode> alarmBatches2AlarmTreeTableDataNodeList(List<AlarmBatch> listBatches) {
306         List<AlarmTreeTableDataNode> sonList = new ArrayList<>();
307         for (AlarmBatch alarmBatch : listBatches) {
308             List<AlarmTreeTableDataNode> grandsonList = new ArrayList<>();
309             List<Alarm> alarmList = alarmBatch.getListAlarms();
310             for (Alarm alarm : alarmList) {
311                 String objectId = alarm.getSignature() + " [" + alarm.getId() + "]";
312                 AlarmTreeTableDataNode grandson = new AlarmTreeTableDataNode(objectId, alarm.getOwnerPackageName(), alarm.getAlarmType(), String.valueOf(alarm.getWhen()),String.valueOf(alarm.getWhen()), null);
313                 grandsonList.add(grandson);
314             }
315             String objectId = alarmBatch.getSignature() + " [" + alarmBatch.getId() + "] (" + alarmBatch.getAlarmCount() + " alarms)";
316             AlarmTreeTableDataNode son = new AlarmTreeTableDataNode(objectId, null, null, null, null, grandsonList);
317             sonList.add(son);
318         }
319         return sonList;
320     }
321 
322     private final class LoadFromDeviceButtonActionListener implements ActionListener {
323         @Override
324         public void actionPerformed(ActionEvent e) {
325             getAlarmInfoStringFromDevice();
326             updateUIFromString();
327         }
328     }
329 
330     private final class LoadFromFileButtonActionListener implements ActionListener {
331         @Override
332         public void actionPerformed(ActionEvent e) {
333             getAlarmInfoStringFromFile();
334             updateUIFromString();
335         }
336     }
337 }