class JavaTracePanel(QWidget): def __init__(self, app, *__args): super().__init__(app) self.app = app self.app.dwarf.onJavaTraceEvent.connect(self.on_event) self.app.dwarf.onEnumerateJavaClassesStart.connect( self.on_enumeration_start) self.app.dwarf.onEnumerateJavaClassesMatch.connect( self.on_enumeration_match) self.app.dwarf.onEnumerateJavaClassesComplete.connect( self.on_enumeration_complete) self.tracing = False self.trace_classes = [] self.trace_depth = 0 layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self._record_icon = QIcon( utils.resource_path('assets/icons/record.png')) self._pause_icon = QIcon(utils.resource_path('assets/icons/pause.png')) self._stop_icon = QIcon(utils.resource_path('assets/icons/stop.png')) self._tool_bar = QToolBar() self._tool_bar.addAction('Start', self.start_trace) self._tool_bar.addAction('Pause', self.pause_trace) self._tool_bar.addAction('Stop', self.stop_trace) self._tool_bar.addSeparator() self._entries_lbl = QLabel('Entries: 0') self._entries_lbl.setStyleSheet('color: #ef5350;') self._entries_lbl.setContentsMargins(10, 0, 10, 2) self._entries_lbl.setAttribute(Qt.WA_TranslucentBackground, True) # keep this self._entries_lbl.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self._entries_lbl.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self._tool_bar.addWidget(self._entries_lbl) layout.addWidget(self._tool_bar) self.setup_splitter = QSplitter() self.events_list = JavaTraceView(self) self.events_list.setVisible(False) self.trace_list = DwarfListView() self.trace_list_model = QStandardItemModel(0, 1) self.trace_list_model.setHeaderData(0, Qt.Horizontal, 'Traced') self.trace_list.setModel(self.trace_list_model) self.trace_list.doubleClicked.connect(self.trace_list_double_click) self.class_list = DwarfListView() self.class_list_model = QStandardItemModel(0, 1) self.class_list_model.setHeaderData(0, Qt.Horizontal, 'Classes') self.class_list.setModel(self.class_list_model) self.class_list.setContextMenuPolicy(Qt.CustomContextMenu) self.class_list.customContextMenuRequested.connect( self.show_class_list_menu) self.class_list.doubleClicked.connect(self.class_list_double_click) self.current_class_search = '' bar = QScrollBar() bar.setFixedWidth(0) bar.setFixedHeight(0) self.trace_list.setHorizontalScrollBar(bar) bar = QScrollBar() bar.setFixedWidth(0) bar.setFixedHeight(0) self.class_list.setHorizontalScrollBar(bar) self.setup_splitter.addWidget(self.trace_list) self.setup_splitter.addWidget(self.class_list) layout.addWidget(self.setup_splitter) layout.addWidget(self.events_list) self.setLayout(layout) def class_list_double_click(self, item): item = self.class_list_model.itemFromIndex(item) try: if self.trace_classes.index(item.text()) >= 0: return except: pass self.trace_classes.append(item.text()) self.trace_list_model.appendRow([QStandardItem(item.text())]) self.trace_list_model.sort(0, Qt.AscendingOrder) def on_enumeration_start(self): self.class_list_model.setRowCount(0) def on_enumeration_match(self, java_class): try: if PREFIXED_CLASS.index(java_class) >= 0: try: if self.trace_classes.index(java_class) >= 0: return except: pass self.trace_list_model.appendRow(QStandardItem(java_class)) self.trace_classes.append(java_class) except: pass self.class_list_model.appendRow([QStandardItem(java_class)]) def on_enumeration_complete(self): self.class_list_model.sort(0, Qt.AscendingOrder) self.trace_list_model.sort(0, Qt.AscendingOrder) def on_event(self, data): trace, event, clazz, data = data if trace == 'java_trace': self.events_list.add_event({ 'event': event, 'class': clazz, 'data': data.replace(',', ', ') }) self._entries_lbl.setText('Events: %d' % len(self.events_list.data)) def pause_trace(self): self.app.dwarf.dwarf_api('stopJavaTracer') self.tracing = False def show_class_list_menu(self, pos): menu = QMenu() search = menu.addAction('Search') action = menu.exec_(self.class_list.mapToGlobal(pos)) if action: if action == search: self.class_list._on_cm_search() def start_trace(self): self.app.dwarf.dwarf_api('startJavaTracer', [self.trace_classes]) self.trace_depth = 0 self.tracing = True self.setup_splitter.setVisible(False) self.events_list.setVisible(True) def stop_trace(self): self.app.dwarf.dwarf_api('stopJavaTracer') self.tracing = False self.setup_splitter.setVisible(True) self.events_list.setVisible(False) self.events_list.clear() def trace_list_double_click(self, model_index): row = self.trace_list_model.itemFromIndex(model_index).row() if row != -1: trace_entry = self.trace_list_model.item(row, 0).text() if not trace_entry: return try: index = self.trace_classes.index(trace_entry) self.trace_classes.pop(index) self.trace_list_model.removeRow(row) except ValueError: pass def keyPressEvent(self, event): if event.modifiers() & Qt.ControlModifier: if event.key() == Qt.Key_F: self.search() super(JavaTracePanel, self).keyPressEvent(event)
class JavaTracePanel(QtWidgets.QWidget): def __init__(self, app, *__args): super().__init__(app) self.app = app self.app.dwarf.onJavaTraceEvent.connect(self.on_event) self.app.dwarf.onEnumerateJavaClassesStart.connect( self.on_enumeration_start) self.app.dwarf.onEnumerateJavaClassesMatch.connect( self.on_enumeration_match) self.app.dwarf.onEnumerateJavaClassesComplete.connect( self.on_enumeration_complete) self.tracing = False self.trace_depth = 0 # a list of classes you generally want to trace self._prefixed_classes = [ 'android.util.Base64', 'java.security.MessageDigest', 'java.util.zip.GZIPOutputStream' ] layout = QtWidgets.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self._record_icon = QtGui.QIcon( utils.resource_path('assets/icons/record.png')) self._pause_icon = QtGui.QIcon( utils.resource_path('assets/icons/pause.png')) self._stop_icon = QtGui.QIcon( utils.resource_path('assets/icons/stop.png')) self._tool_bar = QtWidgets.QToolBar() self._tool_bar.addAction('Start', self.start_trace) self._tool_bar.addAction('Pause', self.pause_trace) self._tool_bar.addAction('Stop', self.stop_trace) self._tool_bar.addSeparator() self._entries_lbl = QtWidgets.QLabel('Events: 0') self._entries_lbl.setStyleSheet('color: #ef5350;') self._entries_lbl.setContentsMargins(10, 0, 10, 2) self._entries_lbl.setAttribute(QtCore.Qt.WA_TranslucentBackground, True) # keep this self._entries_lbl.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) self._entries_lbl.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) self._tool_bar.addWidget(self._entries_lbl) layout.addWidget(self._tool_bar) self.setup_splitter = QtWidgets.QSplitter() self.events_list = JavaTraceView(self) self.events_list.setVisible(False) self.trace_list = DwarfListView() self.trace_list_model = QtGui.QStandardItemModel(0, 1) self.trace_list_model.setHeaderData(0, QtCore.Qt.Horizontal, 'Traced') self.trace_list.setModel(self.trace_list_model) self.trace_list.doubleClicked.connect(self.trace_list_double_click) self.class_list = DwarfListView() self.class_list_model = QtGui.QStandardItemModel(0, 1) self.class_list_model.setHeaderData(0, QtCore.Qt.Horizontal, 'Classes') self.class_list.setModel(self.class_list_model) self.class_list.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.class_list.customContextMenuRequested.connect( self.show_class_list_menu) self.class_list.doubleClicked.connect(self.class_list_double_click) self.current_class_search = '' self.setup_splitter.addWidget(self.trace_list) self.setup_splitter.addWidget(self.class_list) layout.addWidget(self.setup_splitter) layout.addWidget(self.events_list) self.setLayout(layout) def class_list_double_click(self, model_index): class_name = self.class_list_model.item(model_index.row(), 0).text() if class_name: for i in range(self.trace_list_model.rowCount()): if self.trace_list_model.item(i, 0).text() == class_name: return self.trace_list_model.appendRow([QtGui.QStandardItem(class_name)]) self.trace_list_model.sort(0, QtCore.Qt.AscendingOrder) def on_enumeration_start(self): self.class_list.clear() def on_enumeration_match(self, java_class): self.class_list_model.appendRow([QtGui.QStandardItem(java_class)]) if java_class in self._prefixed_classes: for i in range(self.trace_list_model.rowCount()): if self.trace_list_model.item(i, 0).text() == java_class: return self.trace_list_model.appendRow(QtGui.QStandardItem(java_class)) def on_enumeration_complete(self): self.class_list_model.sort(0, QtCore.Qt.AscendingOrder) self.trace_list_model.sort(0, QtCore.Qt.AscendingOrder) def on_event(self, data): trace, event, clazz, data = data if trace == 'java_trace': self.events_list.add_event({ 'event': event, 'class': clazz, 'data': data.replace(',', ', ') }) self._entries_lbl.setText('Events: %d' % len(self.events_list.data)) def pause_trace(self): self.app.dwarf.dwarf_api('stopJavaTracer') self.tracing = False def show_class_list_menu(self, pos): menu = QtWidgets.QMenu() search = menu.addAction('Search') action = menu.exec_(self.class_list.mapToGlobal(pos)) if action: if action == search: self.class_list._on_cm_search() def start_trace(self): trace_classes = [] for i in range(self.trace_list_model.rowCount()): trace_classes.append(self.trace_list_model.item(i, 0).text()) if not trace_classes: return self.app.dwarf.dwarf_api('startJavaTracer', [trace_classes]) self.trace_depth = 0 self.tracing = True self.setup_splitter.setVisible(False) self.events_list.setVisible(True) def stop_trace(self): self.app.dwarf.dwarf_api('stopJavaTracer') self.tracing = False self.setup_splitter.setVisible(True) self.events_list.setVisible(False) self.events_list.clear() def trace_list_double_click(self, model_index): self.trace_list_model.removeRow(model_index.row()) def keyPressEvent(self, event): if event.modifiers() & QtCore.Qt.ControlModifier: if event.key() == QtCore.Qt.Key_F: self.search() super(JavaTracePanel, self).keyPressEvent(event)