0%

Q动态分区 recovey fastbootd 调研

1
2
3
#需要先挂载fastboot
mkdir /config/usb_gadget/g1/functions/ffs.fastboot
mount -t functionfs fastboot /dev/usb-ffs/fastboot

初步调试 清除数据wipe_data进 fastboot, 重启进adb模式

使用wireshark进行调试

1
2
3
4
5
6
7
8
9
10
T:  Bus=01 Lev=01 Prnt=01 Port=08 Cnt=03 Dev#= 40 Spd=480  MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
P: Vendor=18d1 ProdID=4ee0 Rev= 4.19
S: Manufacturer=Xiaomi
S: Product=Umi
S: SerialNumber=4e80ec52
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=500mA
I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=03 Driver=(none)
E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
1
2
3
4
#打包recovery的ramdisk
out/host/linux-x86/bin/mkbootfs -d out/target/product/umi/system out/target/product/umi/recovery/root | out/host/linux-x86/bin/minigzip > out/target/product/umi/ramdisk-recovery.img
#打包recovery.img
out/host/linux-x86/bin/mkbootfs -d out/target/product/umi/system out/target/product/umi/recovery/root | out/host/linux-x86/bin/minigzip > out/target/product/umi/ramdisk-recovery.img && out/host/linux-x86/bin/mkbootimg --kernel out/target/product/umi/kernel --ramdisk out/target/product/umi/ramdisk-recovery.img --cmdline "console=ttyMSM0,115200n8 androidboot.hardware=qcom androidboot.console=ttyMSM0 androidboot.memcg=1 lpm_levels.sleep_disabled=1 video=vfb:640x400,bpp=32,memsize=3072000 msm_rtb.filter=0x237 service_locator.enable=1 androidboot.usbcontroller=a600000.dwc3 swiotlb=2048 loop.max_part=7 cgroup.memory=nokmem,nosocket reboot=panic_warm androidboot.selinux=permissive androidboot.usbconfigfs=true" --base 0x00000000 --pagesize 4096 --recovery_dtbo out/target/product/umi/prebuilt_dtbo.img --dtb out/target/product/umi/dtb.img --os_version 10 --os_patch_level 2019-09-05 --header_version 2 --output out/target/product/umi/recovery.img

OTA测试环境OTA地址

1
http://husky.pt.miui.com/buildFile/miui_UMI_9.9.20_f2a2d4cc2d_10.0.zip

1. 关于hidl service

1.1. hal简介

HAL 接口定义语言(简称 HIDL,发音为“hide-l”)是用于指定 HAL 和其用户之间的接口的一种接口描述语言. 用于进程间通信.分为直通式(passthrough)和绑定式(binderized)

1.2. hidl服务的调用流程

以android.hardware.fastboot为例, 具体实现在default. defalut是默认实例, 最后编译为动态库

1
name: "android.hardware.fastboot@1.0-impl-mock",

在client端调用IFastboot::getService, 能编译通过的前提是client端引用了动态库 android.hardware.fastboot@1.0

该库文件对应的代码是IFastboot.hal. 定义了相关IFastboot的接口.

1
2
3
4
5
6
[~/work_space/q9/hardware/interfaces/fastboot/1.0] - [日 9月 29, 14:54]
[$] -git:(bsp-umi-q*)> tree
.
├── Android.bp
├── IFastboot.hal
└── types.hal

由 update-makefiles.sh脚本对hal文件进行解析, 生成在out/soong/.intermediates/hardware/interfaces/fastboot/1.0/android.hardware.fastboot@1.0_genc++_headers/gen/android/hardware/fastboot/1.0/IFastboot.h

1
2
3
4
5
6
7
8
9
namespace android {
namespace hardware {
namespace fastboot {
namespace V1_0 {
struct IFastboot : public ::android::hidl::base::V1_0::IBase {
using getPartitionType_cb = std::function<void(::android::hardware::fastboot::V1_0::FileSystemType type, const ::android::hardware::fastboot::V1_0::Result& result)>;
static ::android::sp<IFastboot> getService(const std::string &serviceName="default", bool getStub=false);
virtual ::android::hardware::Return<void> getPartitionType(const ::android::hardware::hidl_string& partitionName, getPartitionType_cb _hidl_cb) = 0;
...

android.hardware.fastboot@1.0_genc++/gen/android/hardware/fastboot/1.0/FastbootAll.cpp

首先看下getService的相关实现:

1
2
3
::android::sp<IFastboot> IFastboot::getService(const std::string &serviceName, const bool getStub) {
return ::android::hardware::details::getServiceInternal<BpHwFastboot>(serviceName, true, getStub);
}

该函数接下来会调用到libhidlbase.so里, 具体实现在system/libhidl/transport/include/hidl/HidlTransportSupport.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <typename BpType, typename IType = typename BpType::Pure,
typename = std::enable_if_t<std::is_same<i_tag, typename IType::_hidl_tag>::value>,
typename = std::enable_if_t<std::is_same<bphw_tag, typename BpType::_hidl_tag>::value>>
sp<IType> getServiceInternal(const std::string& instance, bool retry, bool getStub) {
using ::android::hidl::base::V1_0::IBase;
sp<IBase> base = getRawServiceInternal(IType::descriptor, instance, retry, getStub);
...
if (base->isRemote()) {
// getRawServiceInternal guarantees we get the proper class
return sp<IType>(new BpType(getOrCreateCachedBinder(base.get())));
}

return IType::castFrom(base);
}
1
libhidlbase.so  <--  (static_lib)-- libhidltransport-impl-internal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//system/libhidl/transport/ServiceManageMent.cpp
sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
const std::string& instance,
bool retry, bool getStub) {
Transport transport = Transport::EMPTY;
if (kIsRecovery) {
transport = Transport::PASSTHROUGH;
} else {
// 1. waitForHwServiceManager(); 一直等待hwservicemanager.ready变为true. 1s检查一次
// 依赖hwservicemanager
sm = defaultServiceManager1_1();
// 2. 调用ServiceManager的getTransport函数,获取传入的hidl服务的接口类型.
// getTransport函数逻辑较长, 另行分析.
Return<Transport> transportRet = sm->getTransport(descriptor, instance);
...
transport = transportRet;
}
// 3. 接口类型要么是hwbinder, 要么是passthrough, 要么是legacy的
const bool vintfHwbinder = (transport == Transport::HWBINDER);
const bool vintfPassthru = (transport == Transport::PASSTHROUGH);
// 4. 接口类型是hwbinder或者是legacy的. getStub false
for (int tries = 0; !getStub && (vintfHwbinder || vintfLegacy); tries++) {
if (waiter == nullptr && tries > 0) {
waiter = new Waiter(descriptor, instance, sm);
}
if (waiter != nullptr) {
waiter->reset(); // don't reorder this -- see comments on reset()
}
Return<sp<IBase>> ret = sm->get(descriptor, instance);
sp<IBase> base = ret;
if (base != nullptr) {
Return<bool> canCastRet =
details::canCastInterface(base.get(), descriptor.c_str(), true /* emitError */);

if (canCastRet.isOk() && canCastRet) {
if (waiter != nullptr) {
waiter->done();
}
return base; // still needs to be wrapped by Bp class.
}

if (!handleCastError(canCastRet, descriptor, instance)) break;
}

// In case of legacy or we were not asked to retry, don't.
if (vintfLegacy || !retry) break;

if (waiter != nullptr) {
ALOGI("getService: Trying again for %s/%s...", descriptor.c_str(), instance.c_str());
waiter->wait(true /* timeout */);
}
}

if (waiter != nullptr) {
waiter->done();
}
// 5. 接口类型是passthrough的,
if (getStub || vintfPassthru || vintfLegacy) {
// 5.1 创建passThroughManager
const sp<IServiceManager> pm = getPassthroughServiceManager();
if (pm != nullptr) {
// 5.2 getService
sp<IBase> base = pm->get(descriptor, instance).withDefault(nullptr);
if(base==nullptr) {
ALOGI("base nullptr\n");
}
if (!getStub || trebleTestingOverride) {
base = wrapPassthrough(base);
}
return base;
}
}

return nullptr;
}
}

1.3. recovery中hidl环境

上面的代码中注意如果是recovery模式, 直接返回接口类型是passThrough的, 不再解析接口描述文件(manifest.xml), 直接创建passThroughManager.

这里我们先看下passthrough方式接入的后续流程:

1
2
3
4
5
6
7
8
// 5.2 getService
Return<sp<IBase>> get(const hidl_string& fqName,
const hidl_string& name) override {
sp<IBase> ret = nullptr;
// 通过openLibs函数查找相关的库文件

openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
IBase* (*generator)(const char* name);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 static void openLibs(
const std::string& fqName,
const std::function<bool /* continue */ (void* /* handle */, const std::string& /* lib */,
const std::string& /* sym */)>& eachLib) {
// /odm/lib64/hw/ /vendor/lib64/hw/ /system/lib64/vndk-sp%s/hw
// recovery编译中没有定义__ANDROID_VNDK__, 所以多加了 /system/lib64/hw 项
static std::string halLibPathVndkSp = android::base::StringPrintf(
HAL_LIBRARY_PATH_VNDK_SP_FOR_VERSION, details::getVndkVersionStr().c_str());
std::vector<std::string> paths = {
HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR, halLibPathVndkSp,
#ifndef __ANDROID_VNDK__
HAL_LIBRARY_PATH_SYSTEM,
#endif
};
// 查找规则, 传入android.hardware.fastboot@1.0::IFastboot
std::string packageAndVersion = fqName.substr(0, fqName.find("::"));
std::string ifaceName = fqName.substr(idx + strlen("::"));
for (const std::string& path : paths) {
std::vector<std::string> libs = findFiles(path, prefix, ".so");
if (kIsRecovery || path == HAL_LIBRARY_PATH_SYSTEM) {
// recovery中 dlopen 打开lib库
handle = dlopen(fullPath.c_str(), dlMode);
} else {
#if !defined(__ANDROID_RECOVERY__)
handle = android_load_sphal_library(fullPath.c_str(), dlMode);#endif
}
// 寻找HIDL_FETCH_IFastboot函数
*(void **)(&generator) = dlsym(handle, sym.c_str());
if(!generator) {
dlclose(handle);
return true;
}
// 调用HIDL_FETCH_IFastboot函数, 创建IFastboot对端的实例
ret = (*generator)(name.c_str());
}

IFastboot对端的实例提供了hal中定义的接口的实现.default(instance)下的实现

1
2
3
4
5
6
[~/work_space/q9/hardware/interfaces/fastboot/1.0/default] - [日 9月 29, 15:20]
[$] -git:(bsp-umi-q*)> tree
.
├── Android.bp
├── Fastboot.cpp
└── Fastboot.h
1
2
3
4
//Fastboot.cpp
extern "C" IFastboot* HIDL_FETCH_IFastboot(const char* /* name */) {
return new Fastboot();
}

在1217适配方案中因keymaster的改动替换了libhidlbase.so库(recovery编译–>主系统编译的, 丢失了kIsRecovery和__ANDROID_RECOVERY__ ANDROID_VNDK). 直接替换的方式会对recovery的运行环境产生了影响. 表现在如果未启动hwservicemanager.

只要在recovery的相关进程中执行了<接口>::getService, 会一直等待hwservicemanager.ready属性变为true, getService一直处于阻塞状态.

在调试fastbootd时, 执行fastboot getvar all命令无响应, 原因就是fastbootd初始化时, 加载fastboothal, 而调用了IFastboot::getService, 由于libhidlbase替换为主系统的, 又没执行hwservicemanager, 所以一直在等待hwservicemanager.ready=true, 从而处于阻塞状态, fastbootd服务阻塞在构造函数中, 没有回发准备好的状态, 所以fastboot 客户端无法将命令传给对端, 阻塞在发包的地方.

1.4. hidl接口描述(getTransport)

上面的流程中已大致了解了recovery下的hidl环境(主要是passthrough类型的怎么接入的), 下面主要介绍下非recovery模式下的hidl环境. 从调用ServiceManager的getTransport函数,获取传入的hidl服务的接口类型说起

首先是函数接口, 编译通过的前提.

1
2
3
4
5
6
7
8
9
10
// system/libhidl/transport/manager/1.0/IServiceManager.hal   
/**
* Get the transport of a service.
*
* @param fqName Fully-qualified interface name.
* @param name Instance name. Same as in IServiceManager::add
*
* @return transport Transport of service if known.
*/
getTransport(string fqName, string name) generates (Transport transport);

实现在hwservicemanager中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// system/hwservicemanager/ServiceManager.cpp
Return<ServiceManager::Transport> ServiceManager::getTransport(const hidl_string& fqName,
const hidl_string& name) {
using ::android::hardware::getTransport;

if (!mAcl.canGet(fqName, getBinderCallingContext())) {
return Transport::EMPTY;
}
// 调用到Vintf
switch (getTransport(fqName, name)) {
case vintf::Transport::HWBINDER:
return Transport::HWBINDER;
case vintf::Transport::PASSTHROUGH:
return Transport::PASSTHROUGH;
case vintf::Transport::EMPTY:
default:
return Transport::EMPTY;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// system/hwservicemanager/Vintf.cpp
vintf::Transport getTransport(const std::string &interfaceName, const std::string &instanceName) {
FQName fqName;
// 先调用GetFrameworkHalManifest加载xml文件, 再通过getTransportFromManifest查找manifest中是否有fqName,instance的描述
// android.hardware.fastboot@1.0::IFastboot default
vintf::Transport tr = getTransportFromManifest(fqName, instanceName,
vintf::VintfObject::GetFrameworkHalManifest());
if (tr != vintf::Transport::EMPTY) {
return tr;
}
tr = getTransportFromManifest(fqName, instanceName,
vintf::VintfObject::GetDeviceHalManifest());
if (tr != vintf::Transport::EMPTY) {
return tr;
}
return vintf::Transport::EMPTY;
}

通过在framwork和device的hal manifest中查找, 主要的实现在libvintf.so库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
std::shared_ptr<const HalManifest> VintfObject::getFrameworkHalManifest(bool skipCache) {
// 通过fetchedOnce 变量判断之前是否已经fetch过
return Get(&mFrameworkManifest, skipCache,
std::bind(&VintfObject::fetchFrameworkHalManifest, this, _1, _2));
}
status_t VintfObject::fetchFrameworkHalManifest(HalManifest* out, std::string* error) {
// /system/etc/vintf/manifest.xml
auto systemEtcStatus = fetchOneHalManifest(kSystemManifest, out, error);
if (systemEtcStatus == OK) {
// /system/etc/vintf/manifest/*.xml
auto dirStatus = addDirectoryManifests(kSystemManifestFragmentDir, out, error);
if (dirStatus != OK) {
return dirStatus;
}

HalManifest productManifest;
// /product/etc/vintf/manifest.xml
auto productStatus = fetchOneHalManifest(kProductManifest, &productManifest, error);
if (productStatus != OK && productStatus != NAME_NOT_FOUND) {
return productStatus;
}
if (productStatus == OK) {
if (!out->addAll(&productManifest, error)) {
if (error) {
error->insert(0, "Cannot add " + kProductManifest + ":");
}
return UNKNOWN_ERROR;
}
}
// /product/etc/vintf/manifest/*
return addDirectoryManifests(kProductManifestFragmentDir, out, error);
} else {
LOG(WARNING) << "Cannot fetch " << kSystemManifest << ": "
<< (error ? *error : strerror(-systemEtcStatus));
}
// /system/manifest.xml
return out->fetchAllInformation(getFileSystem().get(), kSystemLegacyManifest, error);
}

上述解析过程只是将相关manifest.xml的文件内容加载到内存中, 并解析.

fetch的过程中不能出错, 任何一个目录或文件的加载出错, 都会返回error

/system/etc/vintf/manifest.xml和/system/manifest.xml文件只读取一个, 优先读etc下的, 如果etc下有, 就不会再读system/manifest.xml

fetch一个(加载到内存), 解析一个. 通过 HalManifestConverter 进行后续的解析

1
2
3
4
5
6
7
fetchAllInformation(fileSystem, path, gHalManifestConverter, this, error);
status_t fetchAllInformation(const FileSystem* fileSystem, const std::string& path,
const XmlConverter<T>& converter, T* outObject, std::string* error)
{
status_t result = fileSystem->fetch(path, &info, error);
bool success = converter(outObject, info, error);
}

fetchFrameworkHalManifest的结果为HalManifest指针, 通过其getTransport函数查找已经解析的manifest中是否有对应的hidl服务.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//getTransportFromManifest
vintf::Transport tr = getTransportFromManifest(fqName, instanceName,
vintf::VintfObject::GetFrameworkHalManifest());
vm->getTransport(fqName.package(), fqName.getVersion(), fqName.name(), instanceName);
HalManifest->getTransport(fqName.package(), fqName.getVersion(), fqName.name(), instanceName);

// 匹配包名, 版本, instance
bool HalManifest::forEachInstanceOfVersion(
const std::string& package, const Version& expectVersion,
const std::function<bool(const ManifestInstance&)>& func) const {
for (const ManifestHal* hal : getHals(package)) {
bool cont = hal->forEachInstance([&](const ManifestInstance& manifestInstance) {
if (manifestInstance.version().minorAtLeast(expectVersion)) {
return func(manifestInstance);
}
return true;
});
if (!cont) return false;
}
return true;
}
transport = e.transport();
// 返回匹配hidl服务的接口类型 hwbinder/passthrough/empty
return transport;
1
2
3
4
5
6
7
8
9
10
11
<hal format="hidl">
// packagename
<name>android.hidl.manager</name>
<transport>hwbinder</transport>
<version>1.2</version>
<interface>
<name>IServiceManager</name>
<instance>default</instance>
</interface>
<fqname>@1.2::IServiceManager/default</fqname>
</hal>

1.4.1. 小结

上面主要是getTransport的流程, 解析了system/etc/vintf和product/etc/vintf下的manifest xml文件. vendor和odm的流程是一致的, 注意解析的过程中不能出现解析错误 (目录错误, 文件打开错误, 文件损坏等), 出现错误后, 所有之前的解析结果全部作废.

1.5. hwservicemanager中查询hidl服务

getStub为false时, 通过manifest解析transport类型. 以Keymaster为例, 了解下大概的查找流程.

keymaster的接口描述在/vendor/etc/vintf/manifest.xml

这里通过sm->get(descriptor, instance)查询IKeymasterDevice这个hidl服务,得到IBase对象后,在通过IKeymasterDevice::castFrom转换为IKeymasterDevice对象。

1
2
3
Return<sp<IBase>> ret = sm->get(descriptor, instance);
sp<IBase> base = ret;
Return<bool> canCastRet = details::canCastInterface(base.get(), descriptor.c_str(), true /* emitError */);

sm对象来自

1
2
3
4
5
6
7
// hwservicemanager在初始化后, 会注册自己成为ContextManager   
// ProcessState::self()->becomeContextManager(nullptr, nullptr);
// getContextObject(0) 就是拿的manager对象
using IServiceManager1_2 = android::hidl::manager::V1_2::IServiceManager;
gDefaultServiceManager =
fromBinder<IServiceManager1_2, BpHwServiceManager, BnHwServiceManager>(
ProcessState::self()->getContextObject(nullptr));

sm->get的实现在android.hidl.manager@1.2中.

system/libhidl/transport/manager/1.2/

1
2
3
4
5
6
7
//out/soong/.intermediates/system/libhidl/transport/manager/1.2/android.hidl.manager@1.2_genc++/gen/android/hidl/manager/1.2/ServiceManagerAll.cpp
// Methods from ::android::hidl::manager::V1_0::IServiceManager follow.
::android::hardware::Return<::android::sp<::android::hidl::base::V1_0::IBase>> BpHwServiceManager::get(const ::android::hardware::hidl_string& fqName, const ::android::hardware::hidl_string& name){
::android::hardware::Return<::android::sp<::android::hidl::base::V1_0::IBase>> _hidl_out = ::android::hidl::manager::V1_0::BpHwServiceManager::_hidl_get(this, this, fqName, name);
return _hidl_out;
}