autool/DroidBot/core/event_log.py
2026-06-17 19:44:18 +08:00

162 lines
6.0 KiB
Python

"""
Event Log
Platform-agnostic event logging for recording device interactions.
"""
import json
import os
import time
class EventLog:
"""
事件日志类
用于记录设备交互事件,包括开始状态、结束状态、性能分析等。
"""
def __init__(self, device, app, event, profiling_method=None, tag=None):
"""
初始化事件日志
:param device: 设备对象
:param app: 应用对象
:param event: 事件对象
:param profiling_method: 性能分析方法
:param tag: 日志标签
"""
self.device = device
self.app = app
self.event = event
if tag is None:
from datetime import datetime
tag = datetime.now().strftime("%Y-%m-%d_%H%M%S")
self.tag = tag
self.from_state = None
self.to_state = None
self.event_str = None
self.profiling_method = profiling_method
self.trace_remote_file = "/data/local/tmp/event.trace"
self.is_profiling = False
self.sampling = None
# sampling feature was added in Android 5.0 (API level 21)
self.sampling = None
if profiling_method is not None and str(profiling_method) != "full":
# Check device capability safely
if hasattr(device, 'get_sdk_version') and device.get_sdk_version() >= 21:
try:
self.sampling = int(profiling_method)
except:
pass
def to_dict(self):
"""序列化为字典"""
return {
"tag": self.tag,
"event": self.event.to_dict(),
"start_state": self.from_state.state_str if self.from_state else None,
"stop_state": self.to_state.state_str if self.to_state else None,
"event_str": self.event_str
}
def save2dir(self, output_dir=None):
"""保存事件到目录"""
if output_dir is None:
if self.device.output_dir is None:
return
else:
output_dir = os.path.join(self.device.output_dir, "events")
try:
if not os.path.exists(output_dir):
os.makedirs(output_dir)
event_json_file_path = "%s/event_%s.json" % (output_dir, self.tag)
with open(event_json_file_path, "w") as f:
json.dump(self.to_dict(), f, indent=2)
except Exception as e:
self.device.logger.error("Saving event to dir failed, %s" % e)
def save_views(self, output_dir=None):
"""保存视图"""
views = self.event.get_views()
if views and self.from_state and hasattr(self.from_state, 'save_view_img'):
for view_dict in views:
self.from_state.save_view_img(view_dict=view_dict, output_dir=output_dir)
def is_start_event(self):
"""检查是否是启动事件"""
from .abstract_input_event import EventType
if hasattr(self.event, 'event_type') and self.event.event_type == EventType.INTENT:
intent_cmd = getattr(self.event, 'intent', '')
if intent_cmd and hasattr(self.app, 'get_package_name'):
if "start" in str(intent_cmd) and self.app.get_package_name() in str(intent_cmd):
return True
return False
def start(self):
"""开始发送事件"""
if hasattr(self.device, '_last_state') and self.device._last_state is not None:
self.from_state = self.device._last_state
else:
print("Warning: No last state available, using current state as start state.")
self.from_state = self.device.get_current_state()
self.start_profiling()
self.event_str = self.event.get_event_str(self.from_state)
print(f"[DroidBot] Action: {self.event_str}") # 添加打印以确保可见
self.device.logger.info("Action: %s" % self.event_str)
self.device.send_event(self.event)
def start_profiling(self):
"""开始性能分析"""
if self.profiling_method is None:
return
if self.is_profiling:
return
# 尝试使用设备提供的统一接口
if hasattr(self.device, 'start_profiling'):
success = self.device.start_profiling(self.trace_remote_file, self.sampling)
if success:
self.is_profiling = True
return
# 处理启动事件的特殊情况 (Legacy Android support)
# 如果是启动事件,并且应用尚未运行,可能需要修改 Intent
if self.is_start_event():
if hasattr(self.app, 'get_start_with_profiling_intent'):
start_intent = self.app.get_start_with_profiling_intent(self.trace_remote_file, self.sampling)
if hasattr(self.event, 'intent') and hasattr(start_intent, 'get_cmd'):
self.event.intent = start_intent.get_cmd()
self.is_profiling = True
def stop(self):
"""结束发送事件"""
self.stop_profiling()
self.to_state = self.device.get_current_state()
if hasattr(self.device, '_last_state'):
self.device._last_state = self.to_state
self.save2dir()
self.save_views()
def stop_profiling(self, output_dir=None):
"""停止性能分析"""
if self.profiling_method is None:
return
if not self.is_profiling:
return
if output_dir is None:
if self.device.output_dir is None:
return
else:
output_dir = os.path.join(self.device.output_dir, "events")
if not os.path.exists(output_dir):
os.makedirs(output_dir)
event_trace_local_path = "%s/event_trace_%s.trace" % (output_dir, self.tag)
# 尝试使用设备提供的统一接口
if hasattr(self.device, 'stop_profiling'):
self.device.stop_profiling(self.trace_remote_file, event_trace_local_path)