""" 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)