根据给定关键字,解析提取applogcat-log和kmsgcat-log中lcd亮屏记录(上电开始时间/设背光时间等),并计算耗时,结果以表格呈现。(可用来判断异常时间点,屏有没有亮?亮屏慢不慢?)
log.py :
import inspect
class Logger:
"""Simple logging utility with adjustable levels at runtime"""
LEVELS = {'DEBUG': 10, 'INFO': 20, 'WARN': 30, 'ERROR': 40, 'CRIT': 50}
def __init__(self, level_name='INFO'):
self.level = self.LEVELS.get(level_name, 20)
self.crit(f"init log level = {level_name}")
def set_level(self, level_name):
self.level = self.LEVELS.get(level_name, 20)
self.crit(f"set log level = {level_name}")
def _log(self, level_name, *args, **kwargs):
"""Internal logging method: checks level and outputs if allowed"""
if self.LEVELS[level_name] < self.level:
return
# Get caller's frame (skip current _log and specific level methods)
frame = inspect.currentframe().f_back.f_back
funcname = frame.f_code.co_name
lineno = frame.f_lineno
if self.LEVELS.get(level_name) >= self.LEVELS.get("WARN"):
print(f"{funcname} {lineno}: [{level_name}]", *args, **kwargs)
else:
print(f"{funcname} {lineno}:", *args, **kwargs)
def debug(self, *args, **kwargs):
self._log('DEBUG', *args, **kwargs)
def info(self, *args, **kwargs):
self._log('INFO', *args, **kwargs)
def warn(self, *args, **kwargs):
self._log('WARN', *args, **kwargs)
def error(self, *args, **kwargs):
self._log('ERROR', *args, **kwargs)
def crit(self, *args, **kwargs):
self._log('CRIT', *args, **kwargs)
config.json:
{
"combine_file": {
"log_level": "INFO"
},
"parse_log": {
"log_level": "INFO",
"app_keywords": [
"Waking up from",
"setPowerMode to 2",
"Finished setting power mode 2",
"SurfaceControl: setDisplayBrightness"
],
"kernel_keywords": [
"",
"lcm_prepare: enter",
"lcm_prepare: exit",
"lcm_setbacklight_cmdq: bl level"
]
},
"auto_analysis": {
"log_level": "INFO"
}
}
config_loader.py:
import json
import sys
from log import Logger
logger = Logger("INFO")
CONFIG_PATH = "./config.json"
def load_config():
"""Load configuration file. Exit program if loading fails."""
logger.info(f"Loading configuration from {CONFIG_PATH}")
try:
with open(CONFIG_PATH, 'r', encoding='utf-8') as f:
config = json.load(f)
logger.info("Configuration loaded successfully.")
except FileNotFoundError:
logger.error(f"Configuration file not found: {CONFIG_PATH}")
sys.exit(1)
except json.JSONDecodeError as e:
logger.error(f"Invalid JSON format in configuration file: {e}")
sys.exit(1)
except Exception as e:
logger.error(f"Unexpected error while loading configuration: {e}")
sys.exit(1)
logger.info(f"Final configuration:\n{json.dumps(config, indent=4, ensure_ascii=False)}")
return config
config = load_config()
parse_log.py :
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Log Parser Application
Parses log files to analyze screen wake-up time records.
Supports both application logs and kernel logs with configurable log levels.
"""
import datetime
import os
import re
import sys
import tkinter as tk
from tkinter import filedialog
from log import Logger
from config_loader import config
# ----------------------------------------------------------------------
# Configuration & Constants
# ----------------------------------------------------------------------
APP_KEYWORDS = tuple(config["parse_log"]["app_keywords"])
KERNEL_KEYWORDS = tuple(config["parse_log"]["kernel_keywords"])
logger = Logger(config["parse_log"]["log_level"])
# Time patterns used to extract timestamps from log lines
TIME_PATTERN_1 = r"\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}" # "MM-DD HH:MM:SS.mmm"
TIME_PATTERN_2 = r"\[\s*(\d+\.\d{6})\]" # "[ seconds.microseconds ]"
# Reason pattern for app logs (e.g., "reason=xyz")
REASON_PATTERN = r"reason=([^,]+)"
# Table layout constants
TABLE_FORMAT = "| {:^3} | {:^24} | {:^18} | {:^18} | {:^18} | {:^18} | {:^5} | {:^5} |"
SEPARATOR_LINE = "|-{0:-^3}-+-{0:-^24}-+-{0:-^18}-+-{0:-^18}-+-{0:-^18}-+-{0:-^18}-+-{0:-^5}-+-{0:-^5}-|".format("")
# ----------------------------------------------------------------------
# Redirect stdout/stderr to both console and Tkinter Text widget
# ----------------------------------------------------------------------
class StdoutRedirector:
"""Redirects print output to a Tkinter Text widget while preserving console output."""
def __init__(self, text_widget, original_stream):
"""
Initialize with the target Text widget and the original stream (sys.__stdout__ / sys.__stderr__).
"""
self.text_widget = text_widget
self.original_stream = original_stream
def write(self, message):
"""Write message to original stream and append to Text widget."""
self.original_stream.write(message)
self.text_widget.insert(tk.END, message)
self.text_widget.see(tk.END) # auto-scroll to bottom
self.text_widget.update_idletasks() # keep UI responsive
def flush(self):
"""Required for compatibility with logging and other libraries."""
self.original_stream.flush()
# ----------------------------------------------------------------------
# Data Classes
# ----------------------------------------------------------------------
class LogRecord:
"""Holds parsed information for one screen wake-up event."""
def __init__(self):
"""Initialize fields with default empty values."""
self.reason = "" # extracted reason string
self.logs = ["" for _ in range(4)] # raw log lines (index 0..3)
self.times = ["" for _ in range(4)] # human-readable timestamps (MM-DD HH:MM:SS.mmm)
self.kernel_times = ["" for _ in range(4)] # numeric kernel timestamps (seconds)
self.delta_t12 = 0 # time difference between keyword[1] and keyword[2]
self.delta_t13 = 0 # time difference between keyword[1] and keyword[3]
# ----------------------------------------------------------------------
# Log Parser
# ----------------------------------------------------------------------
class LogParser:
"""Parses log files and builds a list of LogRecord objects."""
def __init__(self, log_keywords):
"""
Initialize parser with a set of 4 keywords to search for.
Args:
log_keywords (tuple): Tuple of 4 keywords (index 0..3).
"""
self.log_keywords = log_keywords
self.records = [] # list of completed LogRecord
self.current_record = LogRecord() # record currently being built
def parse_file(self, file_path):
"""
Parse a log file and return the number of records found.
Args:
file_path (str): Path to the log file.
Returns:
int: Number of parsed records.
"""
logger.info(f"Start parsing file: {file_path}")
# Reset state for a new file
self.records = []
self.current_record = LogRecord()
try:
with open(file_path, 'r', encoding='ISO-8859-1') as file:
lines = file.readlines()
except FileNotFoundError:
logger.error(f"File not found: {file_path}")
return 0
except Exception as e:
logger.error(f"Error reading file: {e}")
return 0
# Process each line
for line in lines:
self._process_line(line)
# Save the last record
self._save_current_record()
logger.info(f"Parse completed, found {len(self.records)} records")
# Debug output of all records
self._debug_print_records()
return len(self.records)
def _process_line(self, line):
"""
Process a single line from the log file.
Args:
line (str): A line of log text.
"""
# ---- Decide if we need to start a new record ----
if self.log_keywords == APP_KEYWORDS:
# For app logs, keywords[0] or keywords[1] indicate the beginning of a new event
if self.log_keywords[0] in line or self.log_keywords[1] in line:
self._save_current_record()
else:
# For kernel logs, only keywords[1] starts a new record
if self.log_keywords[1] in line:
self._save_current_record()
# Loop over all four keywords
for i in range(4):
# Kernel logs skip keyword[0] (it is never used in kernel context)
if self.log_keywords == KERNEL_KEYWORDS and i == 0:
continue
if self.log_keywords[i] in line:
if i == 0:
# Extract the reason from the first matching line
match = re.search(REASON_PATTERN, line)
if match:
self.current_record.reason = match.group(1)
logger.debug(
f"Reason extracted: {match.group(1)} "
f"from line: {line[:-1]}"
)
elif i == 2:
# For keyword[2], we need a valid keyword[1] first and not already set
if self.current_record.logs[1] == "" or self.current_record.logs[2] != "":
break
elif i == 3:
# For keyword[3], we need a valid keyword[2] first
if self.current_record.logs[2] == "" or self.current_record.logs[3] != "":
break
# Store the raw log line
self.current_record.logs[i] = line
time_match = re.search(TIME_PATTERN_1, line)
if time_match:
self.current_record.times[i] = time_match.group()
if self.log_keywords == KERNEL_KEYWORDS:
time_match = re.search(TIME_PATTERN_2, line)
if time_match:
self.current_record.kernel_times[i] = float(time_match.group(1))
logger.debug(f"len(records) = {len(self.records)} "
f"logs[{i}] = {self.current_record.logs[i][:-1]} "
f"times[{i}] = {self.current_record.times[i]} "
f"kernel_times[{i}] = {self.current_record.kernel_times[i]}")
break # Stop after first matching keyword
def _calculate_time_difference(self, index1, index2):
"""
Calculate time difference (in seconds) between two stored timestamps.
Args:
index1 (int): Index of the first timestamp (usually 1).
index2 (int): Index of the second timestamp (2 or 3).
Returns:
float: Time difference in seconds, or 0 on error.
"""
if self.log_keywords == APP_KEYWORDS:
try:
time_format = "%Y-%m-%d %H:%M:%S.%f"
# Write a leap year to avoid errors when the date is 2/29
t1 = f"2024-{self.current_record.times[index1]}"
t2 = f"2024-{self.current_record.times[index2]}"
t1 = datetime.datetime.strptime(t1, time_format)
t2 = datetime.datetime.strptime(t2, time_format)
delta = round((t2 - t1).total_seconds(), 4)
except ValueError as e:
logger.error(f"Time parse error: {e}")
delta = 0
logger.debug(f"{self.current_record.times[index1]} "
f"{self.current_record.times[index2]} {delta}")
else:
delta = round(self.current_record.kernel_times[index2] - self.current_record.kernel_times[index1], 4)
logger.debug(f"{self.current_record.kernel_times[index1]} {self.current_record.kernel_times[index2]} {delta}")
return delta
def _save_current_record(self):
"""Save current record to records list if it is complete."""
# Check if record is complete (has log1 and log2)
if self.current_record.logs[1] != "" and self.current_record.logs[2] != "":
self.current_record.delta_t12 = self._calculate_time_difference(1, 2)
if self.current_record.logs[3] != "":
self.current_record.delta_t13 = self._calculate_time_difference(1, 3)
if self.current_record.delta_t12 >= 0 and self.current_record.delta_t13 >= 0:
logger.debug(f"current_record = {self.current_record.__dict__}")
self.records.append(self.current_record)
self.current_record = LogRecord()
def _debug_print_records(self):
"""Print all records for debugging purposes."""
logger.debug(f"len(records) = {len(self.records)}")
for i, record in enumerate(self.records):
log_output = []
for j in range(4):
log_output.append(
f"record.logs[{j}] = "
f"{record.logs[j][:-1] if record.logs[j] else ''}"
)
logger.debug(
f"i = {i}\n" +
"\n".join(log_output) + "\n"
f"record.times = {record.times}\n"
f"record.kernel_times = {record.kernel_times}\n"
f"record.delta_t12 = {record.delta_t12}\n"
f"record.delta_t13 = {record.delta_t13}\n"
)
def show_results(self, file_path=None):
"""
Display all parse results, optionally writing to a file.
Args:
file_path (str, optional): Output file path. Prints to stdout if None.
"""
out_file = None
if file_path:
try:
out_file = open(file_path, 'w', encoding='utf-8')
except Exception as e:
logger.error(f"Failed to open file {file_path}: {e}")
return
else:
out_file = sys.stdout
# Display by reason groups
unique_reasons = set(record.reason for record in self.records)
try:
for reason in unique_reasons:
self.show_by_reason(reason, out_file)
# Display summary table
self.show_summary(out_file)
finally:
if file_path:
out_file.close()
def show_by_reason(self, reason, out_file):
"""
Show records filtered by reason.
Args:
reason (str): Reason to filter by.
out_file: File-like object for output.
"""
matched_records = [record.delta_t12 for record in self.records if record.reason == reason]
if not matched_records:
return
aver_t12 = round(sum(matched_records) / len(matched_records) * 1000)
print(f"Table for reason = {reason}, average_t12 = {aver_t12} ms", file=out_file)
print(f"{'-' * 134}", file=out_file)
print(TABLE_FORMAT.format("num", "reason", "t0", "t1", "t2", "t3", "t2-t1", "t3-t1"),
file=out_file)
print(SEPARATOR_LINE, file=out_file)
print(TABLE_FORMAT.format("", "",
f"({self.log_keywords[0][:16]})",
f"({self.log_keywords[1][:16]})",
f"({self.log_keywords[2][:16]})",
f"({self.log_keywords[3][:16]})", "(ms)", "(ms)"
), file=out_file)
for i, record in enumerate(self.records):
if record.reason == reason:
print(SEPARATOR_LINE, file=out_file)
t12_ms = round(record.delta_t12 * 1000)
t13_ms = (round(record.delta_t13 * 1000) if record.delta_t13 != 0 else "")
print(TABLE_FORMAT.format(
i, record.reason, record.times[0], record.times[1],
record.times[2], record.times[3], t12_ms, t13_ms
), file=out_file)
print(f"{'-' * 134}\n\n", file=out_file)
def show_summary(self, out_file):
"""
Print a summary table containing all records.
Args:
out_file: File-like object for output.
"""
if not self.records:
logger.warn("No records found")
return
total_t12 = sum(record.delta_t12 for record in self.records)
aver_t12 = round(total_t12 / len(self.records) * 1000)
print(f"Summary table - records: {len(self.records)}, average_t12: {aver_t12} ms", file=out_file)
print('-' * 134, file=out_file)
print(TABLE_FORMAT.format("num", "reason", "t0", "t1", "t2", "t3", "t2-t1", "t3-t1"),
file=out_file)
print(SEPARATOR_LINE, file=out_file)
print(TABLE_FORMAT.format("", "",
f"({self.log_keywords[0][:16]})",
f"({self.log_keywords[1][:16]})",
f"({self.log_keywords[2][:16]})",
f"({self.log_keywords[3][:16]})", "(ms)", "(ms)"
), file=out_file)
for i, record in enumerate(self.records):
print(SEPARATOR_LINE, file=out_file)
t12_ms = round(record.delta_t12 * 1000)
t13_ms = (round(record.delta_t13 * 1000)if record.delta_t13 != 0 else "")
if self.log_keywords == APP_KEYWORDS:
print(TABLE_FORMAT.format(i, record.reason, record.times[0], record.times[1],
record.times[2], record.times[3], t12_ms, t13_ms
), file=out_file)
else:
print(TABLE_FORMAT.format(i, "", "", record.times[1],
record.times[2], record.times[3], "", ""
),file=out_file)
print(TABLE_FORMAT.format("", "", "", record.kernel_times[1],
record.kernel_times[2], record.kernel_times[3],t12_ms, t13_ms
),file=out_file)
print(f"{'-' * 134}\n\n", file=out_file)
# ----------------------------------------------------------------------
# GUI Application
# ----------------------------------------------------------------------
class LogAnalyzerApp:
"""GUI application class."""
def __init__(self):
"""Initialize the GUI application."""
self.root = tk.Tk()
# self.root.geometry("900x700")
# Make the window open maximized (full screen within desktop environment)
self.root.state('zoomed')
self.root.title("Log Parser v1.0")
# Tkinter variables
self.keywords_group = tk.IntVar(value=0) # 0 for app, 1 for kernel
self.log_level = tk.StringVar(value=config["parse_log"]["log_level"])
self.status_var = tk.StringVar(value="Ready")
# Build GUI sections
self._build_control_panel()
self._build_result_area()
self._build_status_bar()
# Redirect output after widgets are created so that self.result_text exists
self._redirect_output_to_widget(self.result_text)
def _build_control_panel(self):
"""Create the top control frame with radio buttons, file selector, etc."""
control_frame = tk.Frame(self.root)
control_frame.pack(fill=tk.X, padx=10, pady=(10, 0))
# --- Radio group for keyword selection ---
radio_frame = tk.Frame(control_frame)
radio_frame.pack(fill=tk.X, pady=(0, 5))
tk.Label(radio_frame, text="Select keywords group:").pack(side=tk.LEFT, padx=(0, 10))
tk.Radiobutton(radio_frame, text="App log keywords", variable=self.keywords_group,
value=0, command=self._update_keywords_display).pack(side=tk.LEFT, padx=(0, 20))
tk.Radiobutton(radio_frame, text="Kernel log keywords", variable=self.keywords_group,
value=1, command=self._update_keywords_display).pack(side=tk.LEFT)
# --- Display the currently selected keywords ---
self.keywords_label = tk.Label(control_frame, width=80, height=4, bg="white",
anchor="w", justify=tk.LEFT, relief=tk.SUNKEN,
padx=5, pady=5)
self.keywords_label.pack(fill=tk.X, pady=(0, 10))
# File selection row (button right, label left with wraplength)
file_frame = tk.Frame(control_frame)
file_frame.pack(fill=tk.X)
# Button packed first to the right to guarantee visibility
tk.Button(file_frame, text="Select Log File", command=self._select_log).pack(side=tk.RIGHT, padx=(10, 0))
# File label fills remaining space, wraps long paths
self.file_label = tk.Label(file_frame,
text="Click the button on the right to select a log file",
anchor="w", justify=tk.LEFT,
relief=tk.GROOVE, padx=5, pady=5, wraplength=600)
self.file_label.pack(side=tk.LEFT, fill=tk.X, expand=True)
# Log level and buttons
setting_frame = tk.Frame(control_frame)
setting_frame.pack(fill=tk.X, pady=(10, 0))
tk.Label(setting_frame, text="Log level:").pack(side=tk.LEFT, padx=(0, 5))
level_menu = tk.OptionMenu(setting_frame, self.log_level, *Logger.LEVELS.keys(),
command=lambda level: logger.set_level(level))
level_menu.config(width=10)
level_menu.pack(side=tk.LEFT, padx=(0, 20))
tk.Button(setting_frame, text="Clear Output", command=self._clear_output).pack(side=tk.RIGHT, padx=(5, 0))
tk.Button(setting_frame, text="Save Report", command=self._save_report).pack(side=tk.RIGHT)
self._update_keywords_display()
def _build_result_area(self):
"""Create the scrollable Text widget for output."""
result_frame = tk.Frame(self.root)
result_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
self.result_text = tk.Text(result_frame, wrap=tk.NONE)
vsb = tk.Scrollbar(result_frame, orient=tk.VERTICAL, command=self.result_text.yview)
hsb = tk.Scrollbar(result_frame, orient=tk.HORIZONTAL, command=self.result_text.xview)
self.result_text.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
self.result_text.grid(row=0, column=0, sticky="nsew")
vsb.grid(row=0, column=1, sticky="ns")
hsb.grid(row=1, column=0, sticky="ew")
result_frame.grid_rowconfigure(0, weight=1)
result_frame.grid_columnconfigure(0, weight=1)
def _build_status_bar(self):
"""Create the bottom status bar."""
status_bar = tk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN,
anchor=tk.W, padx=5, pady=2)
status_bar.pack(side=tk.BOTTOM, fill=tk.X)
def _redirect_output_to_widget(self, text_widget):
"""Replace sys.stdout and sys.stderr with StdoutRedirector instances."""
sys.stdout = StdoutRedirector(text_widget, sys.__stdout__)
sys.stderr = StdoutRedirector(text_widget, sys.__stderr__)
def _update_keywords_display(self):
"""Update keywords display based on selection."""
keywords = APP_KEYWORDS if self.keywords_group.get() == 0 else KERNEL_KEYWORDS
lines = [f"keywords[{i}] = {kw}" for i, kw in enumerate(keywords)]
self.keywords_label.config(text="\n".join(lines))
logger.info(f"Keywords group changed to: {keywords}")
def _select_log(self):
"""Handle 'Select Log File' button: open file dialog, run parser, update status."""
keywords = APP_KEYWORDS if self.keywords_group.get() == 0 else KERNEL_KEYWORDS
log_type = "App Log" if self.keywords_group.get() == 0 else "Kernel Log"
file_path = filedialog.askopenfilename(
title=f"Select {log_type}",
filetypes=[("All files", "*.*"), ("Log", "*.log"), ("Text", "*.txt")]
)
if not file_path:
self.file_label.config(text="No file selected")
logger.info("File selection cancelled")
self.status_var.set("File selection cancelled")
return
# Update label with selected file (will wrap if too long)
self.file_label.config(text=f"Selected: {file_path}")
self.status_var.set("Parsing...")
try:
parser = LogParser(keywords)
parser.parse_file(file_path)
# Display results
parser.show_results()
# parser.show_results("analysis_report.txt")
self.status_var.set(f"Parsing complete, {len(parser.records)} records found.")
except Exception as e:
logger.error(f"Unhandled exception during parsing: {e}")
self.status_var.set("Parsing failed, Check log for details.")
def _clear_output(self):
"""Clear the GUI log text widget and the console screen"""
self.result_text.delete("1.0", tk.END)
os.system("cls") if os.name == "nt" else os.system("clear")
def _save_report(self):
"""Save the current output to a text file."""
content = self.result_text.get("1.0", tk.END).strip()
if not content:
self.status_var.set("Nothing to save")
return
file_path = filedialog.asksaveasfilename(
defaultextension=".txt",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if file_path:
try:
with open(file_path, "w", encoding="utf-8") as f:
f.write(content)
self.status_var.set(f"Report saved to {file_path}")
except Exception as e:
self.status_var.set(f"Save failed: {e}")
def run(self):
"""Start the Tkinter main event loop."""
self.root.mainloop()
def main():
"""Application entry point."""
app = LogAnalyzerApp()
app.run()
if __name__ == "__main__":
main()
测试用例,applogcat-log.txt内容:
11-01 12:34:56.123 1386 2091 I PowerManagerService: Waking up from Asleep (uid=1000, reason=WAKE_REASON_POWER_BUTTON, details=android.policy:POWER)...
2025-11-01 12:34:57.123 895 982 I SurfaceFlinger: setPowerMode to 2 from pid=1386, uid=1000
11-01 12:34:58.124 895 895 I SurfaceFlinger: Finished setting power mode 2 on display 4627039422300187648
11-01 12:34:59.125 1386 2303 I SurfaceControl: setDisplayBrightness. {0.1313524, 68.101685, 0.1313524, 68.101685, 0.13545427, 68.101685}
11-01 12:34:59.456 1386 2303 I SurfaceControl: setDisplayBrightness. {0.1313524, 68.101685, 0.1313524, 68.101685, 0.13545427, 68.101685}
11-01 13:34:57.123 895 982 I SurfaceFlinger: setPowerMode to 2 from pid=1386, uid=1000
11-01 13:34:58.123 895 895 I SurfaceFlinger: Finished setting power mode 2 on display 4627039422300187648
11-01 13:34:59.123 1386 2303 I SurfaceControl: setDisplayBrightness. {0.1313524, 68.101685, 0.1313524, 68.101685, 0.13545427, 68.101685}
11-01 14:34:57.123 895 982 I SurfaceFlinger: setPowerMode to 2 from pid=1386, uid=1000
11-01 14:34:58.123 895 895 I SurfaceFlinger: Finished setting power mode 2 on display 4627039422300187648
模拟其它无关log 11-01 14:34:59.123 Parse LCD screen-on records and time, click to select log file
行 4266: 10-25 10:26:30.125 1386 2091 I PowerManagerService: Waking up from Asleep (uid=1000, reason=WAKE_REASON_TAP, details=android.policy:POWER)...
行 4602: 10-25 10:26:30.176 895 982 I SurfaceFlinger: setPowerMode to 2 from pid=1386, uid=1000
行 6002: 10-25 10:26:30.333 895 895 I SurfaceFlinger: Finished setting power mode 2 on display 4627039422300187648
行 6094: 10-25 10:26:30.339 1386 2303 I SurfaceControl: setDisplayBrightness. {0.1313524, 68.101685, 0.1313524, 68.101685, 0.13545427, 68.101685}
测试用例,kmsgcat-log.txt 内容:
2025-11-01 12:34:57.123 <3>[ 180.123456][ T791] [2025:11:28 02:43:56](0)[791:composer@3.1-se][LCD_KIT/I]lcm_prepare: enter
11-01 12:34:58.124 <3>[ 181.124456][ T791] [2025:11:28 02:43:56](3)[791:composer@3.1-se][LCD_KIT/I]lcm_prepare: exit
11-01 12:34:59.125 <3>[ 182.125456][ T1362] [2025:11:28 02:43:56](3)[1362:AALMain][LCD_KIT/I]lcm_setbacklight_cmdq: bl level:863
11-01 12:34:59.456 <3>[ 183.126456][ T1362] [2025:11:28 02:43:56](3)[1362:AALMain][LCD_KIT/I]lcm_setbacklight_cmdq: bl level:863
11-01 13:34:57.123 <3>[ 181.123456][ T791] [2025:11:28 02:43:56](0)[791:composer@3.1-se][LCD_KIT/I]lcm_prepare: enter
11-01 13:34:58.123 <3>[ 182.124456][ T791] [2025:11:28 02:43:56](3)[791:composer@3.1-se][LCD_KIT/I]lcm_prepare: exit
11-01 13:34:59.123 <3>[ 183.125456][ T1362] [2025:11:28 02:43:56](3)[1362:AALMain][LCD_KIT/I]lcm_setbacklight_cmdq: bl level:863
11-01 14:34:57.123 <3>[ 182.123456][ T791] [2025:11:28 02:43:56](0)[791:composer@3.1-se][LCD_KIT/I]lcm_prepare: enter
11-01 14:34:58.123 <3>[ 183.124456][ T791] [2025:11:28 02:43:56](3)[791:composer@3.1-se][LCD_KIT/I]lcm_prepare: exit
模拟其它无关log [ 2102.724133] 11-01 14:34:59.123 Parse LCD screen-on records and time, click to select log file
行 140: 11-28 02:43:57.268 <3>[ 180.082243][ T791] [2025:11:28 02:43:56](0)[791:composer@3.1-se][LCD_KIT/I]lcm_prepare: enter
行 320: 11-28 02:43:57.396 <3>[ 180.211307][ T791] [2025:11:28 02:43:56](3)[791:composer@3.1-se][LCD_KIT/I]lcm_prepare: exit
行 456: 11-28 02:43:57.451 <3>[ 180.262656][ T1362] [2025:11:28 02:43:56](3)[1362:AALMain][LCD_KIT/I]lcm_setbacklight_cmdq: bl level:863
成品效果:



DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)