首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微信团队分享:iOS版微信是如何防止特殊字符导致的炸群、APP崩溃的?

微信团队分享:iOS版微信是如何防止特殊字符导致的炸群、APP崩溃的?

作者头像
JackJiang
发布2018-08-29 16:48:02
2.6K1
发布2018-08-29 16:48:02
举报
文章被收录于专栏:即时通讯技术即时通讯技术

本文来自微信开发团队yanyang的技术分享。

1、引言

相信大家都遇到过一段特殊文本可以让iOS设备所有app闪退的经历。前段时间大年初一,又出现某个印度语字符引起iOS11系统奔溃,所幸iOS版微信客户端做了保护并没有引起太大问题(字符处理这类技术问题,其实曾在Android版微信上导致过严重的用户体验危机,感兴趣的可以看看文章《微信团队披露:微信界面卡死超级bug“15。。。。”的来龙去脉》)。

一般来说,特殊字符闪退是系统漏洞引起,只要更新系统就行。但大部分用户不愿意更新系统,而苹果也不一定第一时间解决问题。另外后台可以拦截恶意文本传递,但对于本地已下发的消息,后台没有办法让它删除。所以客户端还是要做些保护预防特殊字符闪退。

学习交流:

- 即时通讯开发交流群:320837163[推荐] - 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

(本文同步发布于:http://www.52im.net/thread-1449-1-1.html

2、微信的思路

由于无法事先知道字符串里包含特殊字符,所以只能先让它排版/绘制,看看是否出现问题。做法是,在排版/绘制字符串前,先设置标记位,排版/绘制结束后,移除标记位。

一旦发现标记位存在,就意味着这字符串可能有问题,下次就不显示这个字符串:

这里有几个问题:

有可能在排版/绘制过程中,其它线程crash,导致标记位不能正常移除。所以crash时要判断crash线程是否为排版/绘制线程。

究竟crash多少次才能判断这字符串是有问题的:最早做法是crash一次就直接屏蔽,但很多用户反馈,说某些好友昵称无法显示。其实iOS绘制字符串时也会极少概率出现闪退,从而误判。但crash两次才屏蔽的话,如果用户连续收到N条恶意消息,那么至少crash 2N次才彻底把所有有问题消息屏蔽。

因此,第一次字符串crash先不屏蔽,后续连续字符串crash的话,直接屏蔽。这样crash N+1次就能处理完了。

3、具体的iOS代码实现

正如第2节的思路那样。整个逻辑代码大致如下。

MessageItemView.mm:

//CP是CrashProtected的简称 @implementationMessageItemView - (void)initContentLabel {     m_label = [[MMCPLabel alloc] init];     m_label.cpKey = [MMCPUtil generateKeyWithObject:self.messageModel];     if([MMCPUtil isUnsafeWithKey:m_label.cpKey]) {         // 检测出messageModel消息内容有问题,屏蔽显示         m_label.text = @"该内容无法显示";     } else{         m_label.text = self.messageModel.content;     } } @end

MMCPLabel.mm:

@implementationMMCPLabel @synthesizecpKey = m_cpKey; // 对常用的排版/绘制接口做检查 - (void)layoutSublayersOfLayer:(CALayer *)layer {     CScopedCrashCounter crashCounter(m_cpKey);     [superlayoutSublayersOfLayer:layer]; } - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {     CScopedCrashCounter crashCounter(m_cpKey);     [superdrawLayer:layer inContext:ctx]; } - (CGSize)sizeThatFits:(CGSize)size {     CScopedCrashCounter crashCounter(m_cpKey);     return[supersizeThatFits:size]; } @end

MMCPUtil.mm:

// 利用C++特性,在声明C++类临时变量时,会自动执行构造函数,离开作用域会执行析构函数 // 因此构造函数做crashCount+1,析构函数做crashCount-1 classCScopedCrashCounter { public:     CScopedCrashCounter(NSString*cpKey) {         m_cpKey = cpKey;         [MMCPUtil increaseCrashCountWithKey:m_cpKey];     }     ~CScopedCrashCounter() {         [MMCPUtil decreaseCrashCountWithKey:m_cpKey];     } private:     NSString*m_cpKey; }; @implementationMMCPUtil @synthesizecrashKeyMemoryMappedKV = m_crashKeyMemoryMappedKV; // 被判定为恶意信息对应的key @synthesizecrashCountMemoryMappedKV = m_crashCountMemoryMappedKV; // 每个key crash次数 - (BOOL)isUnsafeWithKey:(NSString*)key {     return[m_crashKeyMemoryMappedKV getBoolForKey:key] == YES; } - (void)increaseCrashCountWithKey:(NSString*)key {     // 这里记录key所在线程     ...     int32_t count = [m_crashCountMemoryMappedKV getInt32ForKey:key];     [m_crashCountMemoryMappedKV setInt32:count + 1 forKey:key] } - (void)decreaseCrashCountWithKey:(NSString*)key {     int32_t count = [m_crashCountMemoryMappedKV getInt32ForKey:key];     [m_crashCountMemoryMappedKV setInt32:MAX(0, count - 1) forKey:key]; } // crash回调函数 - (void)onSignalCrash:(siginfo_t *)info {     // 先找到跟crash线程相同的key     NSString*key = [selflastCPKey:info->si_pid];     if(key == nil) return;     if(m_isLastTimeCrashedBySpecialCharacter == NO) {         // 设置当前是特殊字符引起的闪退,如果crash次数大于1,则屏蔽这字符串显示         [selfsetLastTimeCrashedBySpecialCharacter:YES];         if([m_crashCountMemoryMappedKV getInt32ForKey:key] > 1) {             [m_crashKeyMemoryMappedKV setBool:YESforKey:key];         }     } else{         // 连续特殊字符闪退,直接屏蔽         [m_crashKeyMemoryMappedKV setBool:YESforKey:key];     } } @end

4、还需要从用户体验上做更进一步改进

即使有了上面的N+1优化,当N很大时,客户端还是要crash很多次才能正常使用。之前有用户乱扫二维码被拉进炸群,如果不发红包,群主不停炸群;用户频繁crash,也无法退群。不少用户会选择卸载重装客户端。因此客户端要加上安全模式的机制。

当客户端检测出连续三次crash,下次启动会出现安全模式的界面,提示用户如何处理:

对于频繁闪退的群聊,主界面提供快捷入口方便用户退群。另外对于可能误判的字符串,界面也提供入口方便用户恢复字符串显示:

为了让后台第一时间发现新的特殊字符变种,客户端检测出特殊字符crash后,会把相关信息上报到后台。通过客户端上报、后台拦截的闭环,能大大降低特殊字符传播范围。这方案不仅用于特殊字符,还能用于其他恶意信息,如炸群消息、GIF、小视频、链接等。

5、通用组件MemoryMappedKV

由于需要埋点的地方太多了,昵称、消息内容、头像等等,为了不影响滑动性能,guoling同学开发了一套基于mmap的高性能通用key-value存储组件,敬请留意微信团队公众号的后续技术文章。

附录:有关微信、QQ的文章汇总

[1] QQ、微信团队原创技术文章:微信团队分享:iOS版微信是如何防止特殊字符导致的炸群、APP崩溃的?》 《腾讯技术分享:Android手Q的线程死锁监控系统技术实践》 《微信团队原创分享:iOS版微信的内存监控系统技术实践》 《让互联网更快:新一代QUIC协议在腾讯的技术实践分享》 《iOS后台唤醒实战:微信收款到账语音提醒技术总结》 《腾讯技术分享:社交网络图片的带宽压缩技术演进之路》 《微信团队分享:视频图像的超分辨率技术原理和应用场景》 《微信团队分享:微信每日亿次实时音视频聊天背后的技术解密》 《QQ音乐团队分享:Android中的图片压缩技术详解(上篇)》 《QQ音乐团队分享:Android中的图片压缩技术详解(下篇)》 《腾讯团队分享:手机QQ中的人脸识别酷炫动画效果实现详解》 《腾讯团队分享 :一次手Q聊天界面中图片显示bug的追踪过程分享》 《微信团队分享:微信Android版小视频编码填过的那些坑》  《微信手机端的本地数据全文检索优化之路》  《企业微信客户端中组织架构数据的同步更新方案优化实战》 《微信团队披露:微信界面卡死超级bug“15。。。。”的来龙去脉》 《QQ 18年:解密8亿月活的QQ后台服务接口隔离技术》 《月活8.89亿的超级IM微信是如何进行Android端兼容测试的》 《以手机QQ为例探讨移动端IM中的“轻应用”》 《一篇文章get微信开源移动端数据库组件WCDB的一切!》 《微信客户端团队负责人技术访谈:如何着手客户端性能监控和优化》 《微信后台基于时间序的海量数据冷热分级架构设计实践》 《微信团队原创分享:Android版微信的臃肿之困与模块化实践之路》 《微信后台团队:微信后台异步消息队列的优化升级实践分享》 《微信团队原创分享:微信客户端SQLite数据库损坏修复实践》  《腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率》  《腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(下篇)》  《腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)》  《微信Mars:微信内部正在使用的网络层封装库,即将开源》  《如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源》  《开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石 [源码下载]》  《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解》  《微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)》  《微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)》  《Android版微信从300KB到30MB的技术演进(PPT讲稿) [附件下载]》  《微信团队原创分享:Android版微信从300KB到30MB的技术演进》  《微信技术总监谈架构:微信之道——大道至简(演讲全文)》 《微信技术总监谈架构:微信之道——大道至简(PPT讲稿) [附件下载]》  《如何解读《微信技术总监谈架构:微信之道——大道至简》》 《微信海量用户背后的后台系统存储架构(视频+PPT) [附件下载]》 《微信异步化改造实践:8亿月活、单机千万连接背后的后台解决方案》  《微信朋友圈海量技术之道PPT [附件下载]》  《微信对网络影响的技术试验及分析(论文全文)》  《一份微信后台技术架构的总结性笔记》  《架构之道:3个程序员成就微信朋友圈日均10亿发布量[有视频]》  《快速裂变:见证微信强大后台架构从0到1的演进历程(一)》 《快速裂变:见证微信强大后台架构从0到1的演进历程(二)》  《微信团队原创分享:Android内存泄漏监控和优化技巧总结》  《全面总结iOS版微信升级iOS9遇到的各种“坑”》  《微信团队原创资源混淆工具:让你的APK立减1M》  《微信团队原创Android资源混淆工具:AndResGuard [有源码]》  《Android版微信安装包“减肥”实战记录》  《iOS版微信安装包“减肥”实战记录》  《移动端IM实践:iOS版微信界面卡顿监测方案》  《微信“红包照片”背后的技术难题》  《移动端IM实践:iOS版微信小视频功能技术方案实录》  《移动端IM实践:Android版微信如何大幅提升交互性能(一)》 《移动端IM实践:Android版微信如何大幅提升交互性能(二)》 《移动端IM实践:实现Android版微信的智能心跳机制》  《移动端IM实践:WhatsApp、Line、微信的心跳策略分析》  《移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)》 《移动端IM实践:iOS版微信的多设备字体适配方案探讨》  《信鸽团队原创:一起走过 iOS10 上消息推送(APNS)的坑》 《腾讯信鸽技术分享:百亿级实时消息推送的实战经验》 >> 更多同类文章 …… [2] 有关QQ、微信的技术故事:QQ和微信凶猛成长的背后:腾讯网络基础架构的这些年》 《闲话即时通讯:腾讯的成长史本质就是一部QQ成长史》 《2017微信数据报告:日活跃用户达9亿、日发消息380亿条》 《腾讯开发微信花了多少钱?技术难度真这么大?难在哪?》 《技术往事:创业初期的腾讯——16年前的冬天,谁动了马化腾的代码》  《技术往事:史上最全QQ图标变迁过程,追寻IM巨人的演进历史》  《技术往事:“QQ群”和“微信红包”是怎么来的?》  《开发往事:深度讲述2010到2015,微信一路风雨的背后》  《开发往事:微信千年不变的那张闪屏图片的由来》  《开发往事:记录微信3.0版背后的故事(距微信1.0发布9个月时)》  《一个微信实习生自述:我眼中的微信开发团队》 《首次揭秘:QQ实时视频聊天背后的神秘组织》 >> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-1449-1-1.html

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.03.12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、引言
  • 2、微信的思路
  • 3、具体的iOS代码实现
  • 4、还需要从用户体验上做更进一步改进
  • 5、通用组件MemoryMappedKV
  • 附录:有关微信、QQ的文章汇总
相关产品与服务
图片处理
图片处理(Image Processing,IP)是由腾讯云数据万象提供的丰富的图片处理服务,广泛应用于腾讯内部各产品。支持对腾讯云对象存储 COS 或第三方源的图片进行处理,提供基础处理能力(图片裁剪、转格式、缩放、打水印等)、图片瘦身能力(Guetzli 压缩、AVIF 转码压缩)、盲水印版权保护能力,同时支持先进的图像 AI 功能(图像增强、图像标签、图像评分、图像修复、商品抠图等),满足多种业务场景下的图片处理需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档