View Javadoc
1   package edu.jiangxin.apktoolbox.android.monkey;
2   
3   import edu.jiangxin.apktoolbox.swing.extend.EasyPanel;
4   import edu.jiangxin.apktoolbox.swing.extend.NumberPlainDocument;
5   import edu.jiangxin.apktoolbox.utils.Constants;
6   import edu.jiangxin.apktoolbox.utils.DateUtils;
7   import org.apache.commons.io.IOUtils;
8   
9   import javax.swing.*;
10  import java.awt.*;
11  import java.io.*;
12  import java.nio.charset.StandardCharsets;
13  import java.util.ArrayList;
14  import java.util.List;
15  import java.util.Objects;
16  
17  /**
18   * @author jiangxin
19   * @author 2019-04-12
20   *
21   */
22  public class MonkeyPanel extends EasyPanel {
23  
24      @Serial
25      private static final long serialVersionUID = 1L;
26      
27      private static final String LOG_NAME = "java_monkey_log";
28  
29      private static final String HOUR = "时";
30      private static final String MINUTE = "分";
31      private static final String SECOND = "秒";
32  
33      private static final String CMD = "cmd.exe";
34  
35      private static final String CMD_PS_A = "adb -s ";
36      private static final String CMD_PS_B = " shell ps";
37      private static final String CMD_KILL_A = "adb -s ";
38      private static final String CMD_KILL_B = " shell kill ";
39  
40      private static final String MONKEY = "com.android.commands.monkey";
41  
42      private static final String TRANSACTIONCOUNT = "9999";
43  
44      /**
45       * 设备列表不能为空!
46       */
47      private static final String MSG4 = "设备列表不能为空!请[刷新]!";
48  
49      /**
50       * 应用程序不能为空!
51       */
52      private static final String MSG5 = "应用程序不能为空!请选其他设备!";
53  
54      /**
55       * 事件间隔或时间数量不能为空!
56       */
57      private static final String MSG2 = "事件间隔或时间数量不能为空!";
58  
59      /**
60       * 日志保存路径不能为空!
61       */
62      private static final String MSG6 = "日志保存路径不能为空!";
63  
64      Thread threadTimeType = null;
65      Process monkeyProcess = null;
66  
67      JComboBox<String> comboBoxDevices = new JComboBox<>();
68      JButton refreshButton = new JButton("刷新");
69  
70      JButton logPathButton = new JButton("选择路径");
71      JButton executeButton = new JButton("运行命令");
72  
73      JButton resetButton = new JButton("重置页面");
74      JButton interruptButton = new JButton("终止运行");
75  
76      JLabel labelHour = new JLabel();
77      JLabel labelMinute = new JLabel();
78      JLabel labelSecond = new JLabel();
79      JTextField textMillisecond = new JTextField(30);
80      JTextField textTime = new JTextField(30);
81      JTextField textLogPath = new JTextField(90);
82  
83      JComboBox<String> comboBoxProgram = new JComboBox<>();
84      JComboBox<String> comboBoxTime = new JComboBox<>();
85  
86      /**
87       * --dbg-no-events:初始化启动的activity,但是不产生任何事件
88       */
89      JCheckBox checkBoxDbgNoEvents = new JCheckBox("初始化启动的activity,但是不产生任何事件");
90  
91      /**
92       * --hprof:指定该项后在事件序列发送前后会立即生成分析报告(一般建议指定该项)
93       */
94      JCheckBox checkBoxHprof = new JCheckBox("在事件序列发送前后会立即生成分析报告");
95  
96      /**
97       * --ignore-crashes:忽略崩溃
98       */
99      JCheckBox checkBoxCrashes = new JCheckBox("忽略崩溃", true);
100 
101     /**
102      * --ignore-timeouts:忽略超时
103      */
104     JCheckBox checkBoxTimeouts = new JCheckBox("忽略超时", true);
105 
106     /**
107      * --monitor-native-crashes:跟踪本地方法的崩溃问题
108      */
109     JCheckBox checkBoxNativeCrashes = new JCheckBox("跟踪本地方法的崩溃问题", true);
110 
111     /**
112      * --ignore-security-exceptions:忽略安全异常
113      */
114     JCheckBox checkBoxExceptions = new JCheckBox("忽略安全异常", true);
115 
116     /**
117      * --kill-process-after-error:发生错误后直接杀掉进程
118      */
119     JCheckBox checkBoxKill = new JCheckBox("发生错误后直接杀掉进程");
120 
121     /**
122      * --wait-dbg:知道连接了调试器才执行monkey测试
123      */
124     JCheckBox checkBoxWaitDbg = new JCheckBox("停止Monkey执行,直到有调试器与其连接");
125 
126     ButtonGroup group = new ButtonGroup();
127 
128     /**
129      * 缺省值
130      */
131     JRadioButton radioButton0 = new JRadioButton("基本信息");
132 
133     /**
134      * 比较详细
135      */
136     JRadioButton radioButton1 = new JRadioButton("比较详细");
137 
138     /**
139      * 非常详细(默认选中)
140      */
141     JRadioButton radioButton2 = new JRadioButton("非常详细", true);
142 
143     ArrayList<String> list;
144     int flag = 0;
145     String[] monkeyCmd = null;
146 
147     @Override
148     public void initUI() {
149         setPreferredSize(new Dimension(Constants.DEFAULT_PANEL_WIDTH, Constants.DEFAULT_PANEL_HEIGHT));
150         setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
151 
152         JPanel devicesPanel = new JPanel();
153         devicesPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
154         initDevices(devicesPanel);
155         add(devicesPanel);
156 
157         JPanel programPanel = new JPanel();
158         programPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
159         initProgram(programPanel);
160         add(programPanel);
161 
162         JPanel restrainConditionPanel = new JPanel();
163         restrainConditionPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
164         initRestrainCondition(restrainConditionPanel);
165         add(restrainConditionPanel);
166 
167         JPanel eventIntervalPanel = new JPanel();
168         eventIntervalPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
169         initEventInterval(eventIntervalPanel);
170         add(eventIntervalPanel);
171 
172         JPanel runTimePanel = new JPanel();
173         runTimePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
174         initRunTime(runTimePanel);
175         add(runTimePanel);
176 
177         JPanel logLevelPanel = new JPanel();
178         logLevelPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
179         initLogLevel(logLevelPanel);
180         add(logLevelPanel);
181 
182         JPanel logPathPanel = new JPanel();
183         logPathPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
184         initLogPath(logPathPanel);
185         add(logPathPanel);
186 
187         JPanel operationPanel = new JPanel();
188         operationPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
189         initOperation(operationPanel);
190         add(operationPanel);
191     }
192 
193     private void initDevices(JPanel panel) {
194         JLabel labelDevices = new JLabel("设备列表");
195         labelDevices.setPreferredSize(new Dimension(60, 25));
196         comboBoxDevices.setPreferredSize(new Dimension(240, 25));
197         refreshButton.setPreferredSize(new Dimension(60, 25));
198 
199         panel.add(labelDevices);
200         panel.add(comboBoxDevices);
201         panel.add(refreshButton);
202 
203         refreshButton.addActionListener(e -> {
204             comboBoxDevices.removeAllItems();
205             List<String> devices = getDevices();
206             for (String device : devices) {
207                 comboBoxDevices.addItem(device);
208             }
209         });
210     }
211 
212     private void initProgram(JPanel panel) {
213         JLabel labelProgram = new JLabel("应用程序");
214         labelProgram.setPreferredSize(new Dimension(60, 25));
215         comboBoxProgram.setPreferredSize(new Dimension(240, 25));
216         comboBoxProgram.setEditable(true);
217         comboBoxProgram.setSelectedItem("com.shinow.*");
218 
219         panel.add(labelProgram);
220         panel.add(comboBoxProgram);
221 
222         comboBoxDevices.addActionListener(e -> {
223             comboBoxProgram.removeAllItems();
224             comboBoxProgram.setSelectedItem("com.shinow.*");
225             List<String> programs = getApplication(comboBoxDevices.getSelectedItem().toString());
226             for (String program : programs) {
227                 comboBoxProgram.addItem(program);
228             }
229 
230         });
231     }
232 
233     private void initRestrainCondition(JPanel panel) {
234         JLabel labelRestrain = new JLabel("约束条件");
235         labelRestrain.setPreferredSize(new Dimension(60, 25));
236         checkBoxCrashes.setPreferredSize(new Dimension(100, 25));
237         checkBoxTimeouts.setPreferredSize(new Dimension(100, 25));
238         checkBoxExceptions.setPreferredSize(new Dimension(110, 25));
239         checkBoxNativeCrashes.setPreferredSize(new Dimension(180, 25));
240         checkBoxKill.setPreferredSize(new Dimension(180, 25));
241         checkBoxWaitDbg.setPreferredSize(new Dimension(280, 25));
242         checkBoxHprof.setPreferredSize(new Dimension(280, 25));
243 
244         panel.add(labelRestrain);
245         panel.add(checkBoxCrashes);
246         panel.add(checkBoxTimeouts);
247         panel.add(checkBoxExceptions);
248         panel.add(checkBoxNativeCrashes);
249         panel.add(checkBoxKill);
250         panel.add(checkBoxWaitDbg);
251         panel.add(checkBoxHprof);
252     }
253 
254     private void initEventInterval(JPanel panel) {
255         JLabel labelSpace = new JLabel("事件间隔");
256         labelSpace.setPreferredSize(new Dimension(60, 25));
257         textMillisecond.setPreferredSize(new Dimension(150, 25));
258         textMillisecond.setDocument(new NumberPlainDocument(7));
259         textMillisecond.setText("500");
260         JLabel labelMillisecond = new JLabel("毫秒");
261         labelMillisecond.setPreferredSize(new Dimension(40, 25));
262 
263         panel.add(labelSpace);
264         panel.add(textMillisecond);
265         panel.add(labelMillisecond);
266     }
267 
268     private void initRunTime(JPanel panel) {
269         JLabel labelTime = new JLabel("运行时长");
270         labelTime.setPreferredSize(new Dimension(60, 25));
271         textTime.setPreferredSize(new Dimension(150, 25));
272         textTime.setDocument(new NumberPlainDocument(7));
273         textTime.setText("1");
274         comboBoxTime.setPreferredSize(new Dimension(60, 25));
275         comboBoxTime.addItem(HOUR);
276         comboBoxTime.addItem(MINUTE);
277         comboBoxTime.addItem(SECOND);
278 
279         labelHour.setPreferredSize(new Dimension(50, 25));
280         labelMinute.setPreferredSize(new Dimension(50, 25));
281         labelSecond.setPreferredSize(new Dimension(50, 25));
282 
283         panel.add(labelTime);
284         panel.add(textTime);
285         panel.add(comboBoxTime);
286 
287         panel.add(labelHour);
288         panel.add(labelMinute);
289         panel.add(labelSecond);
290     }
291 
292     private void initLogLevel(JPanel panel) {
293         JLabel labelLogLevel = new JLabel("日志级别");
294         labelLogLevel.setPreferredSize(new Dimension(60, 25));
295 
296         group.add(radioButton0);
297         group.add(radioButton1);
298         group.add(radioButton2);
299 
300         radioButton0.setPreferredSize(new Dimension(80, 25));
301         radioButton1.setPreferredSize(new Dimension(80, 25));
302         radioButton2.setPreferredSize(new Dimension(80, 25));
303 
304         panel.add(labelLogLevel);
305         panel.add(radioButton0);
306         panel.add(radioButton1);
307         panel.add(radioButton2);
308     }
309 
310     private void initLogPath(JPanel panel) {
311         logPathButton.setPreferredSize(new Dimension(100, 25));
312         textLogPath.setColumns(60);
313         textLogPath.setEditable(false);
314         textLogPath.setText("D:");
315 
316         panel.add(logPathButton);
317         panel.add(textLogPath);
318 
319         logPathButton.addActionListener(e -> {
320             if (e.getSource() == logPathButton) {
321                 JFileChooser fileChooser = new JFileChooser();
322                 fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
323                 int intRetVal = fileChooser.showOpenDialog(new Label());
324                 if (intRetVal == JFileChooser.APPROVE_OPTION) {
325                     textLogPath.setText(fileChooser.getSelectedFile().getPath());
326                 }
327             }
328         });
329     }
330 
331     private void initOperation(JPanel panel) {
332         executeButton.setPreferredSize(new Dimension(100, 25));
333         resetButton.setPreferredSize(new Dimension(100, 25));
334         interruptButton.setPreferredSize(new Dimension(100, 25));
335 
336         panel.add(executeButton);
337         panel.add(resetButton);
338         panel.add(interruptButton);
339 
340         interruptButton.setEnabled(false);
341 
342         executeButton.addActionListener(e -> execute());
343 
344         resetButton.addActionListener(e -> reset());
345 
346         interruptButton.addActionListener(e -> interrupt());
347 
348     }
349 
350     private void execute() {
351         String combinedOptionCmd = getCombinedOptionCmd();
352 
353         boolean isOk = checkCondition();
354         if (!isOk) {
355             return;
356         }
357 
358         String logLevel = queryLogLevelString();
359         String logFile = textLogPath.getText() + "\\" + LOG_NAME + DateUtils.getCurrentDateString() + ".txt";
360 
361         monkeyCmd = new String[] { CMD, "/C",
362                 "adb -s " + comboBoxDevices.getSelectedItem() + " shell monkey -p "
363                         + comboBoxProgram.getSelectedItem() + combinedOptionCmd + " --throttle "
364                         + textMillisecond.getText() + "" + logLevel + "" + TRANSACTIONCOUNT + " > " + logFile };
365 
366         logger.info("Monkey: {}", monkeyCmd[2]);
367 
368         flag = 0;
369 
370         try {
371             monkeyProcess = Runtime.getRuntime().exec(monkeyCmd);
372         } catch (Exception ex) {
373             logger.error("Exception", ex);
374         }
375 
376         executeButton.setEnabled(false);
377         resetButton.setEnabled(false);
378         interruptButton.setEnabled(true);
379 
380         // 倒计时文本
381         labelHour.setVisible(true);
382         labelMinute.setVisible(true);
383         labelSecond.setVisible(true);
384 
385         // 获取时间类型
386         String timeType = (String) comboBoxTime.getSelectedItem();
387         long time = Long.parseLong(textTime.getText());
388         if (Objects.equals(timeType, HOUR)) {
389             time *= 3600;
390         } else if (Objects.equals(timeType, MINUTE)) {
391             time *= 60;
392         }
393         threadTimeType = new Thread(new CountdownRunnable(time));
394         threadTimeType.start();
395     }
396 
397     private void reset() {
398         // 重置约束条件
399         checkBoxCrashes.setSelected(true);
400         checkBoxTimeouts.setSelected(true);
401         checkBoxExceptions.setSelected(true);
402         checkBoxNativeCrashes.setSelected(true);
403         // 重置日志级别
404         radioButton0.setSelected(false);
405         radioButton1.setSelected(false);
406         radioButton2.setSelected(true);
407         // 重置事件间隔
408         textMillisecond.setText("500");
409         // 重置运行时长
410         textTime.setText("1");
411     }
412 
413     private void interrupt() {
414         // 杀掉Monkey执行进程
415         interruptThread();
416         executeButton.setEnabled(true);
417         resetButton.setEnabled(true);
418         interruptButton.setEnabled(false);
419     }
420 
421     private String getCombinedOptionCmd() {
422         String ignoreCrashes = checkBoxCrashes.isSelected() ? " --ignore-crashes" : "";
423         String ignoreTimeouts = checkBoxTimeouts.isSelected() ? " --ignore-timeouts" : "";
424         String monitorNativeCrashes = checkBoxNativeCrashes.isSelected() ? " --monitor-native-crashes" : "";
425         String ignoreSecurityExceptions = checkBoxExceptions.isSelected() ? " --ignore-security-exceptions" : "";
426         String hprof = checkBoxHprof.isSelected() ? " --hprof" : "";
427         String killProcessAfterError = checkBoxKill.isSelected() ? " --kill-process-after-error" : "";
428         String waitDbg = checkBoxWaitDbg.isSelected() ? " --wait-dbg" : "";
429         String dbgNoEvents = checkBoxDbgNoEvents.isSelected() ? "--dbg-no-events" : "";
430         return ignoreCrashes + ignoreTimeouts + ignoreSecurityExceptions + monitorNativeCrashes + hprof
431                 + killProcessAfterError + waitDbg + dbgNoEvents;
432     }
433 
434     private boolean checkCondition() {
435         // 判断设备列表和应用程序是否为空
436         if (comboBoxDevices.getItemCount() == 0) {
437             new MyDialog(MSG4).setVisible(true);
438             refreshButton.requestFocus();
439             return false;
440         }
441         if (comboBoxProgram.getItemCount() == 0) {
442             new MyDialog(MSG5).setVisible(true);
443             return false;
444         }
445         // 判断事件间隔和运行时长是否为空
446         if (textMillisecond.getText().length() == 0) {
447             new MyDialog(MSG2).setVisible(true);
448             textMillisecond.requestFocus();
449             return false;
450         }
451         if (textTime.getText().length() == 0) {
452             new MyDialog(MSG2).setVisible(true);
453             textTime.requestFocus();
454             return false;
455         }
456         if (textLogPath.getText().length() == 0) {
457             new MyDialog(MSG6).setVisible(true);
458             logPathButton.requestFocus();
459             return false;
460         }
461         return true;
462     }
463 
464     private String queryLogLevelString() {
465         if (radioButton0.isSelected()) {
466             return " -v ";
467         } else if (radioButton1.isSelected()) {
468             return " -v -v ";
469         } else if (radioButton2.isSelected()) {
470             return " -v -v -v ";
471         }
472         return "";
473     }
474 
475     /**
476      * 中断Monkey命令
477      */
478     public void interruptThread() {
479 
480         logger.info("中断Monkey命令--开始");
481 
482         String[] cmd1 = new String[] { CMD, "/c", CMD_PS_A + comboBoxDevices.getSelectedItem() + CMD_PS_B };
483         executeCommand(cmd1, MONKEY);
484 
485         List<String> listPid = list;
486         logger.info("获取的中断Monkey进程数量:" + listPid.size());
487 
488         String[] cmd2 = null;
489         String pid = "";
490         for (String s : listPid) {
491             pid = s;
492             cmd2 = new String[]{CMD, "/c", CMD_KILL_A + comboBoxDevices.getSelectedItem() + CMD_KILL_B + pid};
493             executeCommand(cmd2, MONKEY);
494         }
495 
496         flag = 1;
497 
498         monkeyProcess.destroy();
499 
500         labelHour.setVisible(false);
501         labelMinute.setVisible(false);
502         labelSecond.setVisible(false);
503 
504         logger.info("中断Monkey命令--结束");
505 
506     }
507 
508     private List<String> getDevices() {
509         List<String> devices = new ArrayList<>();
510         logger.info("get device list start");
511         Process process = null;
512         try {
513             process = Runtime.getRuntime().exec("adb devices");
514         } catch (IOException e) {
515             logger.error("exec command failed: " + e.getMessage());
516         }
517         if (process == null) {
518             logger.error("process is null");
519             return devices;
520         }
521         try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
522             String line;
523             while ((line = reader.readLine()) != null) {
524                 if (line.contains("device") && !line.contains("List of")) {
525                     line = line.substring(0, line.length() - 7);
526                     logger.info("device name: " + line);
527                     devices.add(line);
528                 }
529             }
530         } catch (IOException e) {
531             logger.error("read failed: " + e.getMessage());
532         } finally {
533             IOUtils.closeQuietly(process.getOutputStream());
534             IOUtils.closeQuietly(process.getErrorStream());
535             IOUtils.closeQuietly(process.getInputStream());
536         }
537         logger.info("get device list end");
538         return devices;
539     }
540 
541     private List<String> getApplication(String device) {
542         List<String> apps = new ArrayList<>();
543         logger.info("get application list start");
544         Process process = null;
545         try {
546             process = Runtime.getRuntime().exec(new String[]{"adb", "-s", device, "shell", "pm", "list", "packages"});
547         } catch (IOException e) {
548             logger.error("exec command failed: " + e.getMessage());
549         }
550         if (process == null) {
551             logger.error("process is null");
552             return apps;
553         }
554         try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
555             String line;
556             while ((line = reader.readLine()) != null) {
557                 if (line.contains("package:")) {
558                     logger.info("application name:" + line);
559                     apps.add(line.replace("package:", ""));
560                 }
561             }
562         } catch (IOException e) {
563             logger.error("read failed: " + e.getMessage());
564         } finally {
565             IOUtils.closeQuietly(process.getOutputStream());
566             IOUtils.closeQuietly(process.getErrorStream());
567             IOUtils.closeQuietly(process.getInputStream());
568         }
569         logger.info("get application list end");
570         return apps;
571     }
572 
573     private void executeCommand(String[] cmd, String keyValue) {
574         logger.info("exec cmd start");
575         list = new ArrayList<>();
576         Process process = null;
577         try {
578             process = Runtime.getRuntime().exec(cmd);
579         } catch (IOException e) {
580             logger.error("exec command failed: " + e.getMessage());
581         }
582         if (process == null) {
583             logger.error("process is null");
584             return;
585         }
586         try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
587             String line;
588             while ((line = reader.readLine()) != null) {
589                 if (line.contains(keyValue)) {
590                     line = line.replace(" ", ":");
591                     System.out.println("[" + keyValue + "][" + line + "]");
592                     String[] str = line.split(":");
593                     System.out.println(str.length);
594                     for (int i = 1; i < str.length; i++) {
595                         if (str[i].length() > 0) {
596                             logger.info("Pid: " + str[i]);
597                             list.add(str[i]);
598                             break;
599                         }
600                     }
601                 }
602             }
603         } catch (IOException e) {
604             logger.error("read failed: " + e.getMessage());
605         } finally {
606             IOUtils.closeQuietly(process.getOutputStream());
607             IOUtils.closeQuietly(process.getErrorStream());
608             IOUtils.closeQuietly(process.getInputStream());
609         }
610         logger.info("exec cmd end");
611     }
612 
613     /**
614      * 倒计时
615      * 
616      */
617     class CountdownRunnable implements Runnable {
618         private long times;
619 
620         public CountdownRunnable(long times) {
621             this.times = times;
622         }
623 
624         @Override
625         public void run() {
626             // 自定义倒计时时间
627             long time = times;
628             long hour = 0;
629             long minute = 0;
630             long seconds = 0;
631 
632             if (time >= 0) {
633                 for (int i = 0; i <= time; i++) {
634                     // 监控Monkey命令
635                     monitorMonkey(time, MONKEY);
636                     // 监控Monkey命令操作的App
637                     monitorApp(time, comboBoxProgram.getSelectedItem().toString());
638                     // 判断标识,是否中断操作
639                     System.out.println("flag==1?Interrupt:Continue:" + flag);
640                     if (flag == 1) {
641                         break;
642                     }
643                     hour = time / 3600;
644                     minute = (time - hour * 3600) / 60;
645                     seconds = time - hour * 3600 - minute * 60;
646                     labelHour.setText(hour + HOUR);
647                     labelMinute.setText(minute + MINUTE);
648                     labelSecond.setText(seconds + SECOND);
649                     try {
650                         Thread.sleep(1000);
651                     } catch (InterruptedException e) {
652                         logger.error("InterruptedException {}", e.getMessage());
653                         Thread.currentThread().interrupt();
654                     }
655                     // 正常结束
656                     if (time == 0) {
657                         Thread.currentThread().interrupt();
658                         interruptThread();
659                         executeButton.setEnabled(true);
660                         resetButton.setEnabled(true);
661                         interruptButton.setEnabled(false);
662                     }
663                     i--;
664                     time--;
665                 }
666                 if (flag == 1) {
667                     Thread.currentThread().interrupt();
668                     threadTimeType.interrupt();
669                     executeButton.setEnabled(true);
670                     resetButton.setEnabled(true);
671                     interruptButton.setEnabled(false);
672                 }
673             }
674         }
675 
676         /**
677          * 间隔60秒监控一次运行monkey命令是否为运行状态,或已关闭
678          * 
679          * @param time     当前剩余执行时间
680          * @param keyValue Monkey命令的进程名称
681          */
682         private void monitorMonkey(long time, String keyValue) {
683             if ((time - 1) % 120 == 0) {
684                 logger.info("监控[" + keyValue + "]线程是否执行完毕---开始");
685                 logger.info("每60秒监听一次,此时time的值:" + (time - 1));
686                 String[] cmd = new String[] { CMD, "/c",
687                         CMD_PS_A + comboBoxDevices.getSelectedItem() + CMD_PS_B };
688                 logger.info("当前命令:" + cmd[2]);
689                 executeCommand(cmd, keyValue);
690                 logger.info("当前线程数:" + list.size());
691                 if (list.size() == 0) {
692                     String log = textLogPath.getText();
693                     System.out.println(textLogPath.getText());
694                     String getDate = DateUtils.getCurrentDateString();
695                     // 日志文件路径
696                     String logFile = log.substring(0, log.indexOf("java_monkey_log")) + LOG_NAME + getDate + ".txt";
697                     textLogPath.setText(logFile);
698                     System.out.println("monkeyCmd[2];" + monkeyCmd[2]);
699                     monkeyCmd[2] = monkeyCmd[2].substring(0, monkeyCmd[2].indexOf("java_monkey_log"))
700                             + "java_monkey_log" + getDate + ".txt";
701                     logger.info("Monkey命令已经停止,再次执行");
702                     logger.info("monkeyCmd[2];" + monkeyCmd[2]);
703                     String[] monkeyCommand = new String[] { CMD, "/c", monkeyCmd[2] };
704                     logger.info("执行");
705                     // 再次执行
706                     try {
707                         monkeyProcess = Runtime.getRuntime().exec(monkeyCommand);
708                     } catch (Exception e) {
709                         logger.error("Exception", e);
710                     }
711                 }
712                 logger.info("监控[" + keyValue + "]线程是否执行完毕---结束");
713             }
714         }
715 
716         /**
717          * 间隔60秒监控一次运行app是否是启动状态,或崩溃掉
718          * 
719          * @param time     当前剩余执行时间
720          * @param keyValue App的进程名称
721          */
722         private void monitorApp(long time, String keyValue) {
723             if ((time - 1) % 120 == 0) {
724                 logger.info("监控[" + keyValue + "]线程是否执行完毕---开始");
725                 logger.info("每60秒监听一次,此时time的值:" + (time - 1));
726                 String[] cmd = new String[] { CMD, "/c",
727                         CMD_PS_A + comboBoxDevices.getSelectedItem() + CMD_PS_B };
728                 logger.info("当前命令:" + cmd[2]);
729                 executeCommand(cmd, keyValue);
730                 logger.info("当前线程数:" + list.size());
731                 if (list.size() == 0) {
732                     logger.info("[" + keyValue + "]已经关闭或崩溃,无法继续执行Monkey,退出系统");
733                     logger.info("监控[" + keyValue + "]线程是否执行完毕---结束");
734                     // 杀掉Monkey执行进程
735                     interruptThread();
736                     // System.gc();
737                 }
738                 logger.info("监控[" + keyValue + "]线程是否执行完毕---结束");
739             }
740         }
741     }
742 
743     static class MyDialog extends JDialog {
744 
745         @Serial
746         private static final long serialVersionUID = 1L;
747 
748         MyDialog(String msg3) {
749             super((Frame)null, "提示", true);
750             setSize(320, 180);
751             Container container = getContentPane();
752             container.setLayout(null);
753             JLabel jl = new JLabel(msg3);
754             jl.setBounds(70, 1, 200, 100);
755             JButton jbb = new JButton("确    定");
756             jbb.setBounds(97, 80, 100, 25);
757             container.add(jl);
758             container.add(jbb);
759 
760             // 设置位置
761             int w = (Toolkit.getDefaultToolkit().getScreenSize().width - 320) / 2;
762             int h = (Toolkit.getDefaultToolkit().getScreenSize().height - 180) / 2;
763 
764             setLocation(w, h);
765 
766             jbb.addActionListener(e -> dispose());
767             setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
768         }
769     }
770 }