Android art monitor_android.cc 源码分析

源码分析

#include "monitor.h"

#include 
#include 
#include 

#include 
#include 

#include "art_method.h"
#include "jni/jni_env_ext.h"
#include "palette/palette.h"
#include "thread.h"

// 定义了一个日志标签 EVENT_LOG_TAG_dvm_lock_sample,用于标识锁竞争事件的日志
#define EVENT_LOG_TAG_dvm_lock_sample 20003

namespace art HIDDEN {

// Thread* self:当前线程对象。
// uint32_t wait_ms:线程等待锁的时间(毫秒)。
// uint32_t sample_percent:采样百分比。
// ArtMethod* owner_method:锁持有者的方法。
// uint32_t owner_dex_pc:锁持有者的代码位置(Dex 文件中的程序计数器)。
void Monitor::LogContentionEvent(Thread* self,
                                 uint32_t wait_ms,
                                 uint32_t sample_percent,
                                 ArtMethod* owner_method,
                                 uint32_t owner_dex_pc) {
  // 创建了一个日志上下文对象 ctx,用于记录锁竞争事件的日志。
  android_log_event_list ctx(EVENT_LOG_TAG_dvm_lock_sample);

  const char* owner_filename;
  int32_t owner_line_number;
  // 使用 TranslateLocation 函数将方法和程序计数器(PC)转换为文件名和行号
  TranslateLocation(owner_method, owner_dex_pc, &owner_filename, &owner_line_number);

  // 从 /proc/self/cmdline 文件中读取当前进程的名称,并将其记录到日志中
  // Emit the process name, <= 33 bytes.
  char proc_name[33] = {};
  {
    int fd = open("/proc/self/cmdline", O_RDONLY  | O_CLOEXEC);
    read(fd, proc_name, sizeof(proc_name) - 1);
    close(fd);
    ctx << proc_name;
  }

  // Emit the sensitive thread ("main thread") status. We follow tradition that this corresponds
  // to a C++ bool's value, but be explicit.
  // 记录当前线程是否为“敏感线程”。在 Android 系统中,主线程(main thread)通常被认为是“敏感线程”,
  // 因为它负责处理 UI 事件和用户交互。如果主线程被阻塞(例如等待锁),可能会导致应用程序响应缓慢甚至出现 
  // ANR(Application Not Responding)错误。
  // 遵循了一个传统做法,即用 C++ 的布尔值(bool)来表示线程是否为敏感线程。
  // 在 C++ 中,true 对应于非零值(通常是 1),而 false 对应于 0
  // 尽管布尔值的表示是约定俗成的,但为了代码的可读性和明确性,这里通过定义常量来显式地表示布尔值
  constexpr uint32_t kIsSensitive = 1u;
  constexpr uint32_t kIsNotSensitive = 0u;
  ctx << (Thread::IsSensitiveThread() ? kIsSensitive : kIsNotSensitive);

  // Emit self thread name string.
  // 获取当前线程的名称
  std::string thread_name;
  self->GetThreadName(thread_name);
  ctx << thread_name;

  // Emit the wait time.
  // 记录当前线程等待锁的时间
  ctx << wait_ms;

  // 获取当前线程的代码位置(文件名、行号和方法名),并记录到日志中
  const char* filename = nullptr;
  int32_t line_number;
  std::string method_name;
  {
    uint32_t pc;
    ArtMethod* m = self->GetCurrentMethod(&pc);
    TranslateLocation(m, pc, &filename, &line_number);

    // Emit the source code file name.
    ctx << filename;

    // Emit the source code line number.
    ctx << line_number;

    // Emit the method name.
    method_name = ArtMethod::PrettyMethod(m);
    ctx << method_name;
  }

  // 记录锁持有者的代码位置(文件名、行号和方法名)。如果锁持有者的代码位置与当前线程相同,则使用 - 表示
  // 注意:持有者的文件名有可能为空
  // Emit the lock owner source code file name.
  if (owner_filename == nullptr) {
    owner_filename = "";
  } else if (strcmp(filename, owner_filename) == 0) {
    // Common case, so save on log space.
    owner_filename = "-";
  }
  ctx << owner_filename;

  // Emit the source code line number.
  ctx << owner_line_number;

  // Emit the owner method name.
  std::string owner_method_name = ArtMethod::PrettyMethod(owner_method);
  ctx << owner_method_name;

  // Emit the sample percentage.
  // 记录锁竞争事件的采样百分比
  ctx << sample_percent;

  // 记录日志类型为event日志
  ctx << LOG_ID_EVENTS;

  // Now report to other interested parties.
  // 将锁竞争事件的信息传递给其他组件
  PaletteReportLockContention(self->GetJniEnv(),
                              wait_ms,
                              filename,
                              line_number,
                              method_name.c_str(),
                              owner_filename,
                              owner_line_number,
                              owner_method_name.c_str(),
                              proc_name,
                              thread_name.c_str());
}

}  // namespace art

举例说明

02-10 14:05:43.759  1000  2649 16342 I dvm_lock_sample: [
system_server,
1,
binder:2649_1D,
9865,
AccessibilityWindowManager.java,
1456,
void com.android.server.accessibility.AccessibilityWindowManager.removeAccessibilityInteractionConnection(android.view.IWindow),
-,
1472,
void com.android.server.accessibility.AccessibilityWindowManager.removeAccessibilityInteractionConnection(android.view.IWindow),
2733]

dvm_lock_sample日志的各个信息为:

  • 进程:system_server
  • 线程:binder:2649_1D
  • 锁等待时间:9865ms
  • 当前线程的代码位置:
    • 文件:AccessibilityWindowManager.java
    • 行号:1456
    • 方法:void removeAccessibilityInteractionConnection(android.view.IWindow)
  • 锁持有者的代码位置:
  • 文件:AccessibilityWindowManager.java(与当前线程相同)
    • 行号:1472
    • 方法:void removeAccessibilityInteractionConnection(android.view.IWindow)
  • 采样百分比:2733

从这条日志可以看出:
当前线程和锁持有者处于同一个文件和方法中。
锁等待时间较长(9865ms),这可能表明存在性能问题,尤其是在主线程(敏感线程)中。

你可能感兴趣的:(android)