ubuntu 22.04.2编译Android 12.1源代码&模拟器

Android 11系统映像可直接将 ARM 指令转换成 x86 指令,因此以前很多需要真机测试的情况,现在只需要模拟器就可以进行操作了。

不过,根据官方博客 Run ARM apps on the Android Emulator 尾部的一段注意事项:

Note that the ARM to x86 translation technology enables the execution of intellectual property owned by Arm Limited. It will only be available on Google APIs and Play Store system images, and can only be used for application development and debug purposes on x86 desktop, laptop, customer on-premises servers, and customer-procured cloud-based environments. The technology should not be used in the provision of commercial hosted services.

这段事项说明,自己编译的镜像是没办法用上这个功能的,必须是Google编译好的镜像。

由于众所周知的原因,我们是没办法正常下载Android的源代码的,因此只能使用国内的镜像来操作了。

1.安装repo工具以及依赖

2.在需要存储代码的地方创建文件夹

3.使用镜像下载Android源代码

清华大学的镜像

4.Android 模拟器编译(可选)

编译完成之后,产生的模拟器可执行文件及库文件都位于external/qemu/objs/android目录下:

后面就可以像执行 SDK 中的模拟器那样,执行我们编译的模拟器了:

5.列出android-12全部分支

6.编译Android 12系统镜像

7.引入编译环境变量

8.设置编译目标,此处我们指定编译x86_64下的完整调试版本(镜像无法安装ARM应用)

9.如果需要跟踪调试代码,建议编译为调试类型

10.编译

注意此处如果发生编译失败,原因基本上是编译顺序导致的引用出错,也就是某些模块还没有编译完成,其他模块已经开始尝试链接,导致依赖错误,此时只要把多线程并发编译修改成单线程编译即可,即直接执行

如果由于内存不足导致的编译失败,可以增加物理内存。但是如果内存无法增加的话,那么适当增加交换分区/交换文件的大小(建议配置16GB以上的交换分区)可以解决此问题,只是编译速度会下降。

运行镜像

选择system-qemu.img和vendor-qemu.img,这两个镜像是专门为qemu运行制作的,如果选择system.img 和vendor.img,则avd运行失败。

上面运行起来的镜像是从~/AndSrc/aosp/out/debug/target/product/generic/hardware-qemu.ini即可读取配置信息的,但是这个文件直接修改无效,我们如果需要修改参数,只能从启动参数中设置。
比如我们如果需要增大内存,开启GPU的支持,则执行如下命令:

编译支持ARM应用的镜像

尽管根据

Note that the ARM to x86 translation technology enables the execution of intellectual property owned by Arm Limited. It will only be available on Google APIs and Play Store system images, and can only be used for application development and debug purposes on x86 desktop, laptop, customer on-premises servers, and customer-procured cloud-based environments. The technology should not be used in the provision of commercial hosted services.

我们自己编译的镜像是没办法直接从源代码编译支持安装运行 ARM 应用的。

但是有两个变通方案:

  1. Google官方的 Android 12 镜像中提取需要的文件塞到我们自己编译的镜像里,参考方案: Adding ARM native bridge to the AOSP11 x86 emulatorandroid_vendor_google_emu-x86
  2. 使用 Intel Houdini 实现支持,参考方案:Include Intel Houdini in Android-x86

参考链接


macOS TimeMachine恢复隐藏文件

macOS自带的时间机器(TimeMachine)还是很好用的,只是如果误删的文件是隐藏文件,操作起来稍微复杂了一些。具体参考如下:

  1. Open the Terminal.

  2. Run the following command:

  3. Go to the location of the missing hidden folder and invoke Time Machine to restore it.

  4. Run the following command to hide files:

参考链接


How to access hidden files to restore in Time Machine

Xcode 12.x添加iOS 10.x模拟器

背景

笔者昨天遇到个问题,有用户反馈在iOS 10.3.1的手机上,有个网页打开白屏。但是问题是笔者手头都没有10.x版本的手机,所以想安装模拟器来尝试复现。

然而,笔者发现电脑上的Xcode版本是12.5.1,已经不支持iOS 10.3.1的模拟器下载了。

继续阅读Xcode 12.x添加iOS 10.x模拟器

MMKV编译报错Invalid `Podfile` file: undefined method `exists?' for File:Class.

尝试在 Flutter 上使用 MMKV1.2.16)的时候,编译报错,如下:

这个问题是由于 cocoapods 升级到 1.12 版本之后,依赖的 ruby 升级到 3.2 版本,其中的 File.exists 函数被替换成 File.exist,导致编译异常。

刚刚开始以为是 Flutter 的原因,结果发现 Flutter 3.7.7版本已经修复这个问题。

尝试了半天,才发现是 MMKV 的问题,主要是 MMKViOS 工程下 flutter/example/ios/Podfileflutter/example/mmkvpodhelper.rb里面的代码需要进行适配。

使用上面的代码替换 File.exists 即可。

参考链接


关于HTTP请求走私的小记

0x00 写在前面

之前一次线上赛,遇到一道Web题,涉及了HTTP请求走私。由于之前未学习过,从而我展开了HTTP请求走私的学习之旅。

0x01 HTTP请求走私是什么

HTTP请求走私是一种干扰网站处理从一个或多个用户接收的HTTP请求序列的方式的技术。使攻击者可以绕过安全控制,未经授权访问敏感数据并直接危害其他应用程序用户。

0x02 为什么会产生HTTP请求走私

请求走私漏洞成因

前端服务器(CDN)和后端服务器接收数据不同步,引起对客户端传入的数据理解不一致,从而导致漏洞的产生。

大多数HTTP请求走私漏洞的出现是因为HTTP规范提供了两种不同的方法来指定请求的结束位置:Content-Length标头和Transfer-Encoding标头。
同时使用两种不同的方法时,Content-Length无效。当使用多个服务器时,对客户端传入的数据理解不一致时,就会出现有些服务器认为Content-Length的长度有效,有些以Transfer-Encoding有效。而一般情况下,反向代理服务器与后端的源站服务器之间,会重用TCP链接。这样超出的长度就会拼接到下一次请求进行请求,从而导致HTTP请求走私漏洞。

RFC2616规范

如果接收的消息同时包含传输编码头字段(Transfer-Encoding)和内容长度头(Content-Length)字段,则必须忽略后者。

由于规范默许可以使用Transfer-EncodingContent-Length处理请求,因此很少有服务器拒绝此类请求。每当我们找到一种方法,将Transfer-Encoding隐藏在服务端的一个chain中时,它将会回退到使用Content-Length去发送请求。

走私攻击实现

当向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,代理服务器可能认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。

扩展:为什么会出现多次请求

这与最为广泛的HTTP 1.1的协议特性——Keep-Alive&Pipeline有关。

HTTP1.0之前的协议设计中,客户端每进行一次HTTP请求,需要同服务器建立一个TCP链接。

而现代的Web页面是由多种资源组成的,要获取一个网页的内容,不仅要请求HTML文档,还有JS、CSS、图片等各种资源,如果按照之前的协议设计,就会导致HTTP服务器的负载开销增大。于是在HTTP1.1中,增加了Keep-AlivePipeline这两个特性。

Keep-Alive:在HTTP请求中增加一个特殊的请求头Connection: Keep-Alive,告诉服务器,接收完这次HTTP请求后,不要关闭TCP链接,后面对相同目标服务器的HTTP请求,重用这一个TCP链接。这样只需要进行一次TCP握手的过程,可以减少服务器的开销,节约资源,还能加快访问速度。这个特性在HTTP1.1中默认开启的。

Pipeline(http管线化):http管线化是一项实现了多个http请求但不需要等待响应就能够写进同一个socket的技术,仅有http1.1规范支持http管线化。在这里,客户端可以像流水线一样发送自己的HTTP请求,而不需要等待服务器的响应,服务器那边接收到请求后,需要遵循先入先出机制,将请求和响应严格对应起来,再将响应发送给客户端。

现在,浏览器默认不启用Pipeline的,但是一般的服务器都提供了对Pipleline的支持。

继续阅读关于HTTP请求走私的小记

Transfer-Encoding 的作用

通过HTTP传送数据时,有些时候并不能事先确定body的长度,因此无法得到Content-Length的值, 就不能在header中指定Content-Length了,造成的最直接的影响就是:接收方无法通过Content-Length得到报文体的长度, 那怎么判断发送方发送完毕了呢?HTTP 1.1协议在header中引入了Transfer-Encoding,当其值为chunked时, 表明采用chunked编码方式来进行报文体的传输

HTTP 1.1中有两个实体头(Entity-Header)直接与编码相关,分别为Content-Encoding和Transfer-Encoding.
先说Content-Encoding, 该头表示实体已经采用了的编码方式.Content-Encoding是请求URL对应实体(Entity)本身的一部分.比如请求URL为http://host/image.png.gz时,可能会得到的Content-Encoding为gzip.Content-Encoding的值是不区分大小写的,目前HTTP1.1标准中已包括的有gzip/compress/deflate/identity等.
与Content-Encoding头对应,HTTP请求中包含了一个Accept-Encoding头,该头用来说明用户代理(User-Agent,一般也就是浏览器)能接受哪些类型的编码. 如果HTTP请求中不存在该头,服务器可以认为用户代理能接受任何编码类型.

接下来重点描述Transfer-Encoding, 该头表示为了达到安全传输或者数据压缩等目的而对实体进行的编码. Transfer-Encoding与Content-Encoding的不同之处在于:
1, Transfer-Encoding只是在传输过程中才有的,并非请求URL对应实体的本身特性.
2, Transfer-Encoding是一个"跳到跳"头,而Content-Encoding是"端到端"头.
该头的用途举例如,请求URL为http://host/abc.txt,服务器发送数据时认为该文件可用gzip方式压缩以节省带宽,接收端看到Transfer-Encoding为gzip首先进行解码然后才能得到请求实体.
此外多个编码可能同时对同一实体使用,所以Transfer-Encoding头中编码顺序相当重要,它代表了解码的顺序过程.同样,Transfer-Encoding的值也是不区分大小写的,目前HTTP1.1标准中已包括的有gzip/compress/deflate/identity/chunked等.
Transfer-Encoding中有一类特定编码:chunked编码.该编码将实体分块传送并逐块标明长度,直到长度为0块表示传输结束, 这在实体长度未知时特别有用(比如由数据库动态产生的数据). HTTP1.1标准规定,只要使用了Transfer-Encoding的地方就必须使用chunked编码,并且chunked必须为最后一层编码.任何HTTP 1.1应用都必须能处理chunked编码.
与Transfer-Encoding对应的请求头为TE,它主要表示请求发起者愿意接收的Transfer-Encoding类型. 如果TE为空或者不存在,则表示唯一能接受的类型为chunked.
其他与Transfer-Encoding相关的头还包括Trailer,它与chunked编码相关,就不细述了.

顾名思义,Content-Length表示传输的实体长度,以字节为单位(在请求方法为HEAD时表示会要发送的长度,但并不实际发送.).Content-Length受Transfer-Encoding影响很大,只要Transfer-Encoding不为identity,则实际传输长度由编码中的chunked决定,Content-Length即使存在也被忽略.

关于HTTP Message Body的长度
在HTTP中有消息体(Message body)和实体(Entity body)之分,简单说来在没有Transfer-Encoding作用时,消息体就是实体,而应用了Transfer-Encoding后,消息体就是编码后的实体,如下:

具体详细的 RFC 7230 说明如下:

参考链接


Transfer-Encoding 的作用

前端万字精华「浏览器简史及其核心原理详解」

今天来聊一聊程序员尤其是前端,离不开的工具「浏览器」。浏览器只要是学习过计算机的小伙伴都不陌生吧?它的主要功能就是向服务器发出请求,在浏览器窗口中展示HTML文档、PDF、图片、视频等网络内容。这些网络资源的位置由用户使用 URI(统一资源标示符)来指定

继续阅读前端万字精华「浏览器简史及其核心原理详解」

Gradle 都做了哪些缓存?

前言

GradleAndroid的构建工具,它的主要目标就是实现快速的编译构建,而这主要就是通过缓存实现的。本文主要介绍Gradle的缓存机制,具体包括以下内容

  1. Gradle缓存机制
  2. Gradle内存缓存
  3. Gradle项目缓存
  4. Gradle本机缓存
  5. Gradle远程缓存

继续阅读Gradle 都做了哪些缓存?

MMKV 高性能的数据存取框架解读

目标

了解MMKV

MMKV的基本应用

MMKV的原理概念

多进程设计思想

性能对比

源码解读

简介

MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强。

官方文档:https://github.com/Tencent/MMKV/blob/master/README_CN.md

项目地址:https://github.com/Tencent/MMKV

继续阅读MMKV 高性能的数据存取框架解读

Flutter this and base files have different roots 问题

Flutter项目是能运行的,打开Flutter里面的Android项目才会报下面错误。

报错的项目配置信息如下:

Flutter一开始Android build是没问题的,开发着突然就报这个下面的错误,开始怀疑是不是有什么缓存啥的,然后各种排除都没找到什么原因,后面想着降版本吧,kotlin降了没用,后面尝试最后一个Gradle降版本竟然成功了。

build.gradle文件

参考链接