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 ()) { 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 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 { sm = defaultServiceManager1_1 (); Return<Transport> transportRet = sm->getTransport (descriptor, instance); ... transport = transportRet; } const bool vintfHwbinder = (transport == Transport::HWBINDER); const bool vintfPassthru = (transport == Transport::PASSTHROUGH); for (int tries = 0 ; !getStub && (vintfHwbinder || vintfLegacy); tries++) { if (waiter == nullptr && tries > 0 ) { waiter = new Waiter (descriptor, instance, sm); } if (waiter != nullptr ) { waiter->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 ); if (canCastRet.isOk () && canCastRet) { if (waiter != nullptr ) { waiter->done (); } return base; } if (!handleCastError (canCastRet, descriptor, instance)) break ; } if (vintfLegacy || !retry) break ; if (waiter != nullptr ) { ALOGI ("getService: Trying again for %s/%s..." , descriptor.c_str (), instance.c_str ()); waiter->wait (true ); } } if (waiter != nullptr ) { waiter->done (); } if (getStub || vintfPassthru || vintfLegacy) { const sp<IServiceManager> pm = getPassthroughServiceManager (); if (pm != nullptr ) { 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 Return<sp<IBase>> get (const hidl_string& fqName, const hidl_string& name) override { sp<IBase> ret = nullptr ; 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 (void * , const std::string& , const std::string& )>& eachLib) { 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 }; 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) { handle = dlopen (fullPath.c_str (), dlMode); } else { #if !defined(__ANDROID_RECOVERY__) handle = android_load_sphal_library (fullPath.c_str (), dlMode);#endif } *(void **)(&generator) = dlsym (handle, sym.c_str ()); if (!generator) { dlclose (handle); return true ; } 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 extern "C" IFastboot* HIDL_FETCH_IFastboot (const char * ) { 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 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 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; } 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 vintf::Transport getTransport (const std::string &interfaceName, const std::string &instanceName) { FQName fqName; 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) { return Get (&mFrameworkManifest, skipCache, std::bind (&VintfObject::fetchFrameworkHalManifest, this , _1, _2)); } status_t VintfObject::fetchFrameworkHalManifest (HalManifest* out, std::string* error) { auto systemEtcStatus = fetchOneHalManifest (kSystemManifest, out, error); if (systemEtcStatus == OK) { auto dirStatus = addDirectoryManifests (kSystemManifestFragmentDir, out, error); if (dirStatus != OK) { return dirStatus; } HalManifest productManifest; 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; } } return addDirectoryManifests (kProductManifestFragmentDir, out, error); } else { LOG (WARNING) << "Cannot fetch " << kSystemManifest << ": " << (error ? *error : strerror (-systemEtcStatus)); } 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 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); 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 (); 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 );
sm对象来自
1 2 3 4 5 6 7 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 ::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; }