最新云音乐Android Cronet接入实践_onet弱网,2024年最新面试官必问的技术问题之一

最后

那我们该怎么做才能做到年薪60万+呢,对于程序员来说,只有不断学习,不断提升自己的实力。我之前有篇文章提到过,感兴趣的可以看看,到底要学习哪些知识才能达到年薪60万+。

通过职友集数据可以查看,以北京 Android 相关岗位为例,其中 【20k-30k】 薪酬的 Android 工程师,占到了整体从业者的 30.8%!

北京 Android 工程师「工资收入水平 」

今天重点内容是怎么去学,怎么提高自己的技术。

1.合理安排时间

2.找对好的系统的学习资料

3.有老师带,可以随时解决问题

4.有明确的学习路线

当然图中有什么需要补充的或者是需要改善的,可以在评论区写下来,一起交流学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

mRequestContext.onRequestStarted();
if (mInitialMethod != null) {
if (!nativeSetHttpMethod(mUrlRequestAdapter, mInitialMethod)) {
throw new IllegalArgumentException("Invalid http method " + mInitialMethod);
}
}
if (mRequestId > 0) {
nativeSetOriginRequestID(mUrlRequestAdapter, mRequestId);
}
// 将业务侧设置的超时时间传递到Cronet
if (connectTime > 0) {
nativeSetConnectTimeoutDuration(mUrlRequestAdapter, (int) connectTime);
}
// 将业务侧设置的超时时间传递到Cronet
if (readTime > 0) {
nativeSetReadTimeoutDuration(mUrlRequestAdapter, (int) readTime);
}

这样上层业务侧无需任何改动既可继续使用 Okhttp 原有能力。

网络请求适配

1、请求维度适配

发起请求时,由原先的通过 Okhttp 内置 interceptor 发起请求切换到使用 Cronet 发起请求后,需要在 Okhttp 接口到 Cronet 接口间做一下请求和响应的适配转换。

网络请求切换示意

同时由于将之前的一些 java 层网络策略下沉到 C++ 实现,之前的一些 java 层的直接调用和传参我们通过基于CronetUrlRequest 进行扩展打通了向 Cronet 的 jni 调用

2、全局调用适配

下沉到 C++ 的网络策略,为尽可能做到和 Cronet 原有代码的解耦,在 C++ 以一个个独立插件形式存在。java 侧通过 CronetRequestContext 设置到 C++ 侧,然后向对应注册的组件进行分发,这个链路上涉及到 java、jni 和C++ 的代码改动,为了降低后续网络策略的开发维护成本,采用了类 JsBridge 的方法,开发了’CppBridge’,将java 和 C++ 之间的方法调用协议化,通过 json 传递数据,这样避免了后续对插件做更新带来的 java 到 C++ 请求链路上繁琐的开发工作,且 C++ 策略可以通过java层的配置中心能力进行动态配置。

解决问题

1、线程优化

众所周知,网络请求需要在子线程中发起,在 Cronet 的官方文档介绍中,推荐通过传入 Executor 来负责执行网络请求:

然后在 okhttp interceptor 中已经是子线程的执行环境,如果仍然传入独立对 executor,会造成不必要的线程切换和时间消耗。通过查看 Cronet 源码,发现其 CronetHttpURLConnection 使用的 MessageLoop 类实现是在当前线程,使用 MessageLoop 即可减少不必要的多余线程引入。

通过 MessageLoop 请求生命周期

2、兼容性解决

不同网络库之间切换,兼容性问题在所难免。虽然同样遵循 http 协议,但是对于一些边界条件的处理不一致或处理严格程度不同也会引起兼容性偏差。篇幅所限,这里仅介绍几个兼容点:

  1. Cronet 库对于http链接数设置为了6个,如果有对于 http 请求的不当使用,例如不正常持有未释放,一旦达到了6个,后续的请求将会 block 直到前序连接资源释放,这在 http1.1 下更容易触发;
  2. Cronet 对请求做了检测,如请求 body 未设置 Content-Type,将会直接抛出异常,
if (!hasContentType) {
    throw new IllegalArgumentException("Requests with upload data must have a Content-Type.");
}

在某些特殊设置情况下,存在有 request body 未设置 Content-Type 的情况将会直接导致请求抛异常;

  1. Cronet 请求返回4xx时,会直接抛出异常,而 okhttp 是通过将结果连带 code 返回到上层,交由使用者自己去处理。

兼容性优化没有统一的解决办法,只能见招拆招,通常是向前保证兼容性或推动优化不合理代码来解决。

3、重定向问题解决

Http 请求发生重定向时,请求 header 中的 Host 字段需要更新为新的目标主机地址,否则服务端校验Host字段和实际请求的 host 不一致时会拒绝请求。首先看一下 Okhttp 是如何实现的这个功能:

okhttp 在 RetryAndFollowUpInterceptor 类中,302会触发重新构建请求对象:

之后在 BridgeInterceptor 中,重新设置 Host:

而 Cronet 在 android 侧的默认实现中,并未对此进行更新,查看cronet代码:

类:cronet_url_request.cc

可以看到,cronet 下层接口是支持对重定向时传入修改的 header 的,但是默认传入了空,也没有提供暴露给 java 侧的接口来进行设置。

解决方案:对 cronet 重定向时更新 header 的能力进行打通,新增设置接口:

void CronetURLRequest::NetworkTasks::SetRedirectHeader(
    const std::string& key,
    const std::string& value) {
  DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
  DCHECK(url_request_.get());
  if (redirect_request_headers_ == base::nullopt) {
    redirect_request_headers_ = base::make_optional<net::HttpRequestHeaders>();
  }
  redirect_request_headers_->SetHeader(key, value);
}

在重定向时将从 java 侧设置下来的 header 传入:

  @Override
    protected void handleRedirectReceived(UrlRequest request, UrlResponseInfo info, String newLocationUrl) {
        try {
            Uri newUri = Uri.parse(newLocationUrl);
            String host = newUri.getHost();
            // 更新Host
            request.setRedirectHeader("Host", host);
            request.followRedirect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

cronet 执行 FollowDeferredRedirect (真正重定向的方法)时,将原有方法替换为传入重定向 header 的方法:

void CronetURLRequest::NetworkTasks::FollowDeferredRedirect() {
  DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
#if defined(WOW_BUILD)
  url_request_->FollowDeferredRedirect(
      this->redirect_request_headers_ /* modified_request_headers */);
#else
  url_request_->FollowDeferredRedirect(
      base::nullopt /* modified_request_headers */);
#endif
}

灰度&上线

网络库切换牵扯业务的方方面面,影响面较大,上线需要格外谨慎:

  1. 在上线前的开发阶段,在开发环境提前切换到 Cronet,如果有问题可以尽早暴露;

  2. 灰度阶段反复分流验证,结合稳定性平台和舆情信息反馈观察,确保 Cronet sdk 的稳定性;

  3. 技术上,为了防止有其他异常情况引起的网络不可用,对非网络抖动引起的网络请求异常自动降级到 Okhttp,达到一定次数后开始彻底降低回 Okhttp,并上报日志进行分析;对网络组件以最小粒度进行动态配置,保证根据任意的组件都可以按需更新/开闭以进行线上ab效果观测;对网络请求各阶段的进行全面端到端数据埋点。

  4. 上线后,拉长观测周期,分阶段放量。反复从各个维度比对网络性能数据,发现异常数据及时分析定位解决,确保数据是完全正向的。分析维度包括:

    • 首包时长/请求时长
    • 错误率
    • 长尾数据分析
    • 业务体感数据这个阶段相对较为漫长,通常是从数据侧发现问题后,结合对应的业务场景去进一步定位问题,在针对不同具体错误类型的数据分析过程中,我们也发现了一些上层非正常使用带来的错误率问题,并一起促进优化降低了部分场景的错误率。

目前 android cronet 已经线上全量稳定运行了一年多时间,从统计数据来看,主站api请求时长有16%的优化,错误率有4%的优化,cdn请求不同域名也有不同程度的优化。

后续规划

弱网场景的特殊优化是业务开发中经常遇到的,云音乐基于 Cronet 的 nqe 模块做二次开发,对外提供弱网检测通知能力(正在进行中);

Cronet 的一个核心功能便是支持 quic 协议,作为下一代的网络通信协议,quic 协议具有一系列的协议层面优化:

1、 更少的建链 RTT

2、链接迁移

不同于 tcp 的四元组标识,quic 使用 cid 作为标识,cid 不变即可维持 quic 连接不中断

3、解决tcp队头阻塞(head of line blocking)问题

4、拥塞控制算法实现

将固化在操作系统实现的 tcp 拥塞控制等算法在应用层实现,无需升级操作系统即可实现对算法的升级

5、更好的安全性

2022年6月6日,IETF 正式发布了 http3 协议,云音乐在线上也小范围进行了 quic 协议的测试,在部分场景下quic 表现了更优秀的网络性能。当然在线上想充分利用 quic 的全部特性例如:连接恢复时的0RTT、链接迁移等特性,还需要对服务端前端机集群进行相应的改造。后续云音乐也会对这业界方面进展持续保持关注。

Android 学习笔录

Android 性能优化篇:https://qr18.cn/FVlo89
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集:https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap

学习宝典

对我们开发者来说,一定要打好基础,随时准备战斗。不论寒冬是否到来,都要把自己的技术做精做深。虽然目前移动端的招聘量确实变少了,但中高端的职位还是很多的,这说明行业只是变得成熟规范起来了。竞争越激烈,产品质量与留存就变得更加重要,我们进入了技术赋能业务的时代。

不论遇到什么困难,都不应该成为我们放弃的理由!

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我针对Android程序员,我这边给大家整理了一套学习宝典!包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

roid必备知识点】**

[外链图片转存中…(img-9vqvb25h-1715375649365)]

【Android部分高级架构视频学习资源】

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 11
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值