make_tapi_happy
今天看到微博上一个热门的讨论:
因为以前有看过一个库的源码,所以一看到 stack_logging_enable_logging ,我就知道大概啥原因了。其实从变量名也就很直观能看出来了,详细的可以继续往下。
这个文件名可以说是意味深长:make_tapi_happy.h。
那问题来了,这个 stack_logging_enable_logging 到底是干啥的?
/* WeChat references this, only god knows why. This symbol does nothing. */
extern int stack_logging_enable_logging;
This symbol does nothing. 说明了该符号在iOS系统中确实没用。那WeChat用它来干啥呢?既然WeChat用到了,说明这个 stack_logging_enable_logging 以前肯定有用,只是苹果后来去掉了而已。那我们就来翻一翻libmalloc的历史版本,都在 libmalloc 这里了。
libmalloc-166.251.2
一直回溯到 libmalloc-166.251.2 ,这也是挺久之前到版本了。里边就有 stack_logging_enable_logging ,并且非常关键。
下边代码仅贴了关键部分:
// To be used in _malloc_initialize_once() only, call that function instead.
static void
_malloc_initialize(void *context __unused)
{
......
// Only setup stack logging hooks once lazy initialization is complete, the
// malloc_zone calls above would otherwise initialize malloc stack logging,
// which calls into malloc re-entrantly from Libc upcalls and so deadlocks
// in the lazy initialization os_once(). rdar://13046853
if (stack_logging_enable_logging) {
switch (stack_logging_mode) {
case stack_logging_mode_malloc:
malloc_logger = __disk_stack_logging_log_stack;
break;
case stack_logging_mode_vm:
__syscall_logger = __disk_stack_logging_log_stack;
break;
case stack_logging_mode_all:
malloc_logger = __disk_stack_logging_log_stack;
__syscall_logger = __disk_stack_logging_log_stack;
break;
case stack_logging_mode_lite:
__syscall_logger = __disk_stack_logging_log_stack;
create_and_insert_lite_zone_while_locked();
enable_stack_logging_lite();
break;
case stack_logging_mode_vmlite:
__syscall_logger = __disk_stack_logging_log_stack;
break;
}
}
......
}
这部分代码中,如果 stack_logging_enable_logging 被设置了1,则会给 malloc_logger 等赋值。这个一个函数指针,用于记录内存分配。
而 turn_on_stack_logging 和 turn_off_stack_logging 则分别用于 开启和关闭 这个 stack_logging_enable_logging 开关。
boolean_t
turn_on_stack_logging(stack_logging_mode_type mode)
{
boolean_t ret = false;
MALLOC_LOCK();
if (!stack_logging_enable_logging) {
if (__uniquing_table_memory_was_deleted()) {
// It would great to be able re-enable even if the uniquing table has been deleted
// <rdar://problem/25014005> malloc stack logging should be able to recreate the uniquing table if needed
} else {
switch (mode) {
case stack_logging_mode_all:
__prepare_to_log_stacks(false);
malloc_logger = __disk_stack_logging_log_stack;
__syscall_logger = __disk_stack_logging_log_stack;
stack_logging_mode = mode;
stack_logging_enable_logging = 1;
ret = true;
malloc_report(ASL_LEVEL_INFO, "recording malloc and VM allocation stacks to disk using standard recorder\n");
break;
......
void
turn_off_stack_logging()
{
MALLOC_LOCK();
if (stack_logging_enable_logging) {
switch (stack_logging_mode) {
case stack_logging_mode_all:
malloc_logger = NULL;
__syscall_logger = NULL;
stack_logging_enable_logging = 0;
malloc_report(ASL_LEVEL_INFO, "turning off recording malloc and VM allocation stacks to disk using standard recorder\n");
break;
......
libmalloc-283
其实,苹果从 libmalloc-283 开始做了修改。libmalloc-283/private/make_tapi_happy.h。
_malloc_initialize 中便没有了 stack_logging_enable_logging 相关的代码。而 turn_on_stack_logging 和 turn_off_stack_logging 分别如下:
#pragma mark -
#pragma mark Malloc Stack Logging - Legacy stubs
/*
* legacy API for MallocStackLogging.
*
* TODO, deprecate this, move clients off it and delete it. Clients should move
* to MallocStackLogging.framework for these APIs.
*/
MALLOC_EXPORT
boolean_t
turn_on_stack_logging(stack_logging_mode_type mode)
{
malloc_register_stack_logger();
if (!msl.dylib) {
return false;
}
boolean_t (*msl_turn_on_stack_logging) (stack_logging_mode_type mode);
msl_turn_on_stack_logging = _dlsym(msl.dylib, "msl_turn_on_stack_logging");
if (!msl_turn_on_stack_logging) {
return false;
}
return msl_turn_on_stack_logging(mode);
}
MALLOC_EXPORT
void turn_off_stack_logging(void)
{
malloc_register_stack_logger();
if (!msl.dylib) {
return;
}
void (*msl_turn_off_stack_logging) ();
msl_turn_off_stack_logging = _dlsym(msl.dylib, "msl_turn_off_stack_logging");
if (msl_turn_off_stack_logging) {
msl_turn_off_stack_logging();
}
}
也就是说,已经不需要 stack_logging_enable_logging 了,取而代之的事 msl.dylib 中的一个 msl_turn_off_stack_logging 符号。
关于这个符号,目前还不清楚其内部原理。有必要单独研究一下。
Matrix
到这里,就已经知道了是 Matrix 使用到了 stack_logging_enable_logging 符号。
Matrix 是一款微信研发并日常使用的应用性能接入框架,支持iOS, macOS和Android。 Matrix 通过接入各种性能监控方案,对性能监控项的异常数据进行采集和分析,输出相应的问题分析、定位与优化建议,从而帮助开发者开发出更高质量的应用。
而其使用 stack_logging_enable_logging 的关键代码如下:
int enable_memory_logging(const char *log_dir)
{
err_code = MS_ERRC_SUCCESS;
#ifdef USE_PRIVATE_API
// stack_logging_enable_logging
int *stack_logging_enable_logging = (int *)dlsym(RTLD_DEFAULT, "stack_logging_enable_logging");
if (stack_logging_enable_logging != NULL && *stack_logging_enable_logging != 0) {
is_debug_tools_running = true;
}
#endif
......
Matrix使用了 RTLD_DEFAULT 中的 stack_logging_enable_logging ,用于开启/关闭内存记录。这是针对 libmalloc-283 之前的版本。
而苹果在libmalloc-283之后,已经去掉了这个 stack_logging_enable_logging ,取而代之的是 msl.dylib 中的 msl_turn_off_stack_logging。所以,在iOS新系统中,Matrix的功能就失效了。看来Matrix 需要继续更新一波了。
make_tapi_happy 这个文件的命名真的是厉害!