make_tapi_happy到底是个啥

7,581 阅读3分钟

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 这个文件的命名真的是厉害!