HAL: 将 HIDL 接口改造为 Stable AIDL

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

1. 定义新的AIDL接口

1.1 编译hidl2aidl工具

1.2 执行转换

1.3 调整编译规则bp文件

2. 向vendor镜像添加AIDL接口

2.1 使用update-api freeze-api管理接口版本

2.2 配置 Framework Compatibility Matrix (FCM兼容性矩阵)

2.3 配置使AIDL编译

2章报错速查

3. 实现service

3.1 编写service代码

3.2 创建service编译规则

3.3 将service添加进系统

3章报错速查

4. 确保service开机启动

4.0 开始配置SEpolicy

4.1 添加新feature目录

4.2 创建 hal_sensorscalibrate_default.te

4.3 创建 file_contexts

4.1 无法启动时的排查方法

5. java层调用service含sepolicy配置


欢迎指正交流谢谢

1. 定义新的AIDL接口

目标将旧接口全部转换为新接口

验证目标肉眼检查所有的接口文件已转换即可

我们使用AOSP自带的转换工具hidl2aidl将旧版hidl接口转换为aidl接口。

1.1 编译hidl2aidl工具

        编译可以在任意位置执行这里以vendor根目录为例

source /opt/conf/openjdk18.conf
source build/envsetup.sh
lunch 项目名-userdebug
m hidl2aidl

1.2 执行转换

        运行hidl2aidl工具。它会读取我们指定的hidl接口并生成转换后的aidl。

        在命令里我们需要指定hidl包的所在位置不然工具会找不到对应的hidl包。

hidl2aidl -o 输出路径 -r hidl包名:hidl包根目录即/1.0的上层目录  hidl包名@要转换的hidl版本

        其中的输出路径我们创建一个aidl文件夹此文件夹与hidl接口1.02.0等文件夹同级。冒号两侧不能有空格。

        例如

hidl2aidl -o vendorabcd/hardware/interfaces/sensorscalibrate/aidl/ -r vendorabcd.hardware.sensorscalibrate:vendorabcd/hardware/interfaces/sensorscalibrate vendorabcd.hardware.sensorscalibrate@1.0

1.3 调整编译规则bp文件

        首先检查转换生成的文件。转换会生成 .aidl 和 Android.bp 两种文件。

.aidl文件

        检查所在路径要与包名匹配。例如包名vendorabcd.hardware.sensorscalibrate文件路径应为 aidl/vendorabcd/hardware/sensorscalibrate/ISensorsCalibrate.aidl

Android.bp文件

        生成的bp文件需要修改示例如下红色部分为需要修改的部分

aidl_interface {

    name: "vendorabcd.hardware.sensorscalibrate",

    vendor_available: true, //这里设置为true因为是vendor目录下的模块

    owner: "vendorabcd", //作为vendor模块需要设定owner才可以通过编译

    srcs: ["vendorabcd/hardware/sensorscalibrate/*.aidl"],

    stability: "vintf", //标示此接口为Stable AIDL必需

    backend: {

        cpp: {

            enabled: false, //产生一个cpp backend.cpp文件unstable

                           //如果想要使用旧版unstable AIDL设置为true

        },

        java: {

            sdk_version: "module_current", //产生一个java backend

                           //默认enabled用来在framework层使用此接口

        },

        ndk: {

            enabled: true, //产生一个ndk backend.cpp文件stable

                           //要使用aidl通信需要ndk后端

                           //不允许使用vndk因为它不是stable

        },

    },

}

2. 向vendor镜像添加AIDL接口

目标通过编译编译生成vendor镜像其中包含aidl接口

验证目标out_hal/soong/.intermediates/system/tools/aidl/build/aidl_metadata_json/此目录下生成了对应的.aidl文件并成功全编译

2.1 使用update-api freeze-api管理接口版本

        AOSP要求我们使用此工具用来管理接口版本。这个工具做的事情是把我们写的接口复制一份然后标上版本号作为一个冻结的stable的版本。之后正式编译时就自动使用它复制出来的版本。

        进入aidl目录即我们为hidl2aidl指定的output目录执行以下命令

source <项目位置>/build/envsetup.sh

lunch 项目名-userdebug

m vendorabcd.hardware.sensorscalibrate-update-api //复制现在的版本到aidl_api/current

m vendorabcd.hardware.sensorscalibrate-freeze-api //从current生成一个新的版本号

        以上命令会生成一个叫aidl_api的目录并在里面做各种修改。我们不要手动修改这个目录的内容。

        以上命令还会在Android.bp中生成一个新的字段versions: [“1”], 代表版本号。这一字段由api工具管理&修改我们不要手动修改这个字段。

2.2 配置 Framework Compatibility Matrix (FCM兼容性矩阵)

        FCM指定了msi与vendor间的兼容关系。因此对我们新定义的接口需要在msi和vendor两个目录中都配置FCM兼容关系。

vendor目录中

        FCM文件位置

        vendor/device/vendorabcd/<机型project名>(/……)/framework_compatibility_matrix.xml

        在FCM文件中我们可能会找到如下的旧版hidl配置

   <hal format="hidl" optional="true">

        <name>vendorabcd.hardware.sensorscalibrate</name>

        <version>1.0</version>

        <interface>

            <name>ISensorsCalibrate</name>

            <instance>default</instance>

        </interface>

   </hal>

        在新的vendor image中我们的新接口将要取代旧接口。因此我们将hidl更改为aidl

    <hal format="aidl" optional="true">

        <name>vendorabcd.hardware.sensorscalibrate</name>

        <version>1.0</version>

        <interface>

            <name>ISensorsCalibrate</name>

            <instance>default</instance>

         </interface>

    </hal>

msi目录中

        FCM文件位置

        msi/device/vendorabcd/<机型project>(/mssi)/framework_compatibility_matrix.xml

        我们希望system image既具有对新版aidl的支持又能够兼容原本的hidl接口。因此这里无需修改直接添加新的aidl接口到文件中

    <hal format="aidl" optional="true">

        <name>vendorabcd.hardware.sensorscalibrate</name>

        <interface>

            <name>ISensorsCalibrate</name>

            <instance>default</instance>

         </interface>

    </hal>

2.3 配置使AIDL编译

        配置vendor镜像编译。我们用aidl取代原本的hidl接口无需保留原有hidl接口。

        首先找到此前的hidl接口编译manifest。它在device/vendorabcd/<project名或chipset>目录下的某个.xml文件之中其中会有类似这样的内容

<manifest version="1.0" type="device">

    <hal format="hidl">

        <name>vendorabcd.hardware.sensorscalibrate</name>

        <transport>hwbinder</transport>

        <version>1.0</version>

        <interface>

            <name>ISensorsCalibrate</name>

            <instance>default</instance>

        </interface>

    </hal>

</manifest>

        我们将其改为aidl

<manifest version="1.0" type="device">

    <hal format="aidl">

        <name>vendorabcd.hardware.sensorscalibrate</name>

        <transport>hwbinder</transport>

        <version>1</version>

        [可以保留原本的写法]

        <interface>

            <name>ISensorsCalibrate</name>

            <instance>default</instance>

        </interface>

      [或者使用fqname]

      <fqname>ISensorsCalibrate/default</fqname>

        [两种任选一个即可]

    </hal>

</manifest>

        现在尝试进行先msi后vendor的全编译。应该能够正常完成整个编译。

        编译完成后会在以下目录中有生成对应的aidl文件

        out_hal/soong/.intermediates/system/tools/aidl/build/aidl_metadata_json/metadata_包名

        以上我们配置的aidl manifest其位置并不强制一定要放在此路径下面。之后我将会移动此manifest的位置将其和service放在一起。您也可以选择之后不移动。

2章报错速查

module "..." already defined

解释包名称重复

错误原因通常是因为原本的hidl接口带有如下结构在接口根目录下的bp文件中定义了如下package root

hidl_package_root {

    name: "vendorabcd.hardware.sensorscalibrate",

}

因此导致了新的aidl接口与旧package root名字冲突。

解决方法修改新的aidl接口的名称。请注意之前的每一步骤中xml文件中的<name>都需要修改。也需要修改.aidl文件中的package名。也需要修改.aidl文件所存放的路径与新接口名称相符合。还需要对应修改Android.bp中的srcs路径。

FAILED: out/soong/...  echo 包名-api missing dependencies

解释找不到对应版本的api

错误原因可能是因为手动修改了Android.bp中的versions字段导致编译工具去寻找一个不存在的版本。

解决方法将versions字段清空并完全删除aidl_api目录。之后再重新执行update-api和freeze-api。

module "包名-api" (created by module "包名_interface"): srcs: No sources provided.

解释srcs目录下没有找到有效的源文件

错误原因Android.bp中srcs配置有问题可能是因为修改了aidl所在目录导致找不到aidl文件。

解决方法修改srcsaidl文件应该直接放在srcs目录内。

files are incompatible: The following instances are in the device manifest but not specified in framework compatibility matrix

解释模块在device manifest中指定了但是找不到对应的FCM

错误原因FCM配置有问题条目未添加或添加了但写错了导致不匹配。

解决方法请检查两个FCM内是否有拼写错误等同时检查manifest中的名字是否写对。

3. 实现service

目标成功编译service

验证目标检查手机中/vendor/bin/hw/目录下是否有service编译出的二进制文件例如/vendor/bin/hw/vendorabcd.hardware.sensorscalibrate-service

        service为一个可执行文件。我们之前步骤中完成的AIDL接口定义了一种信息结构不承担功能。接下来要做的service负责功能执行service会接收AIDL接口发来的信息并处理相关的功能运作。可以用Server-Client模型理解此service即为server端负责处理client端发来的请求并和后台交互以执行功能。

3.1 编写service代码

        首先请在aidl目录下创建一个default目录。我们所有的service相关内容都会放在这个default目录下。

        *理论上service可以放在任何地方但和aidl放在一处更好便于管理。

        进入default目录。我们将要创建三个文件service.cppSensorsCalibrate.hSensorsCalibrate.cpp

service.cpp

        创建这个文件只需修改标红的部分其余照抄即可

#define LOG_TAG "vendorabcd.hardware.sensorscalibrate-service"

#include "SensorsCalibrate.h"

#include <android-base/logging.h>

#include <android/binder_manager.h>

#include <android/binder_process.h>

using aidl::vendorabcd::hardware::sensorscalibrate::SensorsCalibrate;

int main() {

    ABinderProcess_setThreadPoolMaxThreadCount(0);

    std::shared_ptr<SensorsCalibrate> senCal = ndk::SharedRefBase::make<SensorsCalibrate>();

    if (!senCal) {

        return EXIT_FAILURE;

    }

    const std::string instance = std::string() + SensorsCalibrate::descriptor + "/default";

    binder_status_t status = AServiceManager_addService(senCal->asBinder().get(), instance.c_str());

    CHECK(status == STATUS_OK);

    ABinderProcess_joinThreadPool();

    return EXIT_FAILURE;

}

SensorsCalibrate.h

        在这个文件中我们将aidl接口所提供的Bn类扩展为方便使用的类。具体来说我们需要对aidl中的每一个接口都进行一次“翻译”。

        例子如下

#pragma once

#include <aidl/vendorabcd/hardware/sensorscalibrate/BnSensorsCalibrate.h>

namespace aidl {

namespace vendorabcd {

namespace hardware {

namespace sensorscalibrate {

class SensorsCalibrate : public BnSensorsCalibrate{

    ndk::ScopedAStatus SensorsCal(int32_t sensor_type,

                                  int8_t operation_type,

                                  std::string* _aidl_return) override;

};

}  // namespace sensorscalibrate

}  // namespace hardware

}  // namespace vendorabcd

}  // namespace aidl

        标蓝部分和aidl文件中的接口一一对应。我的例子中只有一个方法是因为我的aidl文件只定义了一个接口。对于多个aidl接口我们对每一个都要写一条这样的ndk“翻译”。

        因为我们上一章已经成功编译了aidl标蓝部分的写法可以直接复制。对应文件所在路径为

out/soong/.intermediates/vendorabcd/hardware/interfaces/sensorscalibrate/vendorabcd.hardware.sensorscalibrate-V1-ndk_platform-source/gen/include/aidl/vendorabcd/hardware/sensorscalibrate/BpSensorsCalibrate.h

        其中标红的部分容易混淆请注意路径名。标蓝的部分与aidl文件所在的路径对应。标绿的部分与包名相对应。

        在复制时只需要复制其中的与aidl对应的方法即可。 getInterfaceVersion, getInterfaceHash 、构造析构函数、以及成员变量等都不需要复制。

可看可不看的详细解释

对照来看由.aidl

String SensorsCal(in int sensor_type, in byte operation_type)

改写到.h

ndk::ScopedAStatus SensorsCal(int32_t sensor_type,

                              int8_t operation_type,

                              std::string* _aidl_return) override;

在.h文件中我们将aidl返回值作为最后的参数。.h文件中返回类型改为ndk::ScopedAStatus

SensorsCalibrate.cpp

        此文件直接复制旧版hidl中的对应cpp即可。旧cpp文件可能与hidl定义不在同一处我们已知文件名可以通过搜索找到。

        文件中需要修改以下地方

namespace aidl {

namespace vendorabcd {

namespace hardware {

namespace sensorscalibrate {

namespace V1_0 {

namespace implementation {

Return<void> SensorsCalibrate::SensorsCal(int32_t sensor_type, int8_t operation_type, SensorsCal_cb _hidl_cb) {

ndk::ScopedAStatus SensorsCalibrate::SensorsCal(

                               int32_t sensor_type,

                               int8_t operation_type,

                               std::string* _aidl_return) {//.h声明的一致

    // ……

    // 功能实现部分已省略

    _hidl_cb("Successfully cal prox");

    *_aidl_return = "Successfully cal prox"; //此为hidl/aidl接口返回信息

    return Void();                    

    return ndk::ScopedAStatus::ok();

}

ISensorsCalibrate* HIDL_FETCH_ISensorsCalibrate(const char* /* name */) {

    return new SensorsCalibrate();

}   //hidlFETCH方法现在不需要删除

}  // namespace implementation

}  // namespace V1_0

}  // namespace sensorscalibrate

}  // namespace hardware

}  // namespace vendorabcd

}  // namespace aidl

3.2 创建service编译规则

        要配置编译规则我们在default目录下继续添加以下三个文件Android.mk/bp    .rc    .xml  

Android.mk / Android.bp

        指定service的编译规则。

        具体使用mk文件还是bp文件可以和hidl service保持一致。bp是更现代的方式但如果要引用mk定义的模块则也必须使用mk。因此和hidl版本保持一致是最方便的选择。

        例如hidl版本此service的Android.mk文件如下。我们直接在其上进行修改用作aidl版本service的mk文件

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := vendorabcd.hardware.sensorscalibrate@1.0-service

LOCAL_MODULE := vendorabcd.hardware.sensorscalibrate-service

LOCAL_PROPRIETARY_MODULE := true

LOCAL_MODULE_CLASS := EXECUTABLES

LOCAL_MODULE_RELATIVE_PATH := hw

LOCAL_INIT_RC := vendorabcd.hardware.sensorscalibrate@1.0-service.rc

LOCAL_INIT_RC := vendorabcd.hardware.sensorscalibrate-service.rc

//声明此serviceaidl接口的依赖。之后我们将创建这个文件。

LOCAL_VINTF_FRAGMENTS := vendorabcd.hardware.sensorscalibrate.xml

LOCAL_SRC_FILES := \

    SensorsCalibrate.cpp \

    service.cpp

LOCAL_SHARED_LIBRARIES := \

    libhidlbase \

    libhidltransport \

    libbinder_ndk \ //Stable aidl必需

    libutils \

    libdl \

    liblog \

    libcutils \

    libhardware \

    libbase \

    vendorabcd.hardware.sensorscalibrate@1.0 \

    // 包名-V1-ndk_platform

    vendorabcd.hardware.sensorscalibrate-V1-ndk_platform \

    libhfmanager

include $(BUILD_EXECUTABLE)

.rc

        文件名vendorabcd.hardware.sensorscalibrate-service.rc

        配置开机启动。

        此rc文件将被init.rc链接。我们可以在此文件中指定开机时启动aidl service。示例如下

service vendor.sensorscalibrate-hal /vendor/bin/hw/vendorabcd.hardware.sensorscalibrate-service

//service + 注册名可随意起一个 + 编译后的模块所在路径

    class hal

    user system

    group system

.xml (manifest)

        文件名vendorabcd.hardware.sensorscalibrate.xml

        我把aidl接口的manifest转移到此处因为service依赖于aidl。如果未来不需此service则aidl接口也不编译。这一依赖关系我们已在Android.mk中的LOCAL_VINTF_FRAGMENTS声明过此项配置指向的xml文件即为我们现在创建的xml文件。

        把2.3步中的aidl manifest删除将其中内容转移到default目录下的此文件中。

        内容原样复制即可

<manifest version="1.0" type="device">

    <hal format="aidl">

        <name>vendorabcd.hardware.sensorscalibrate</name>

        <version>1</version>

        <interface>

            <name>ISensorsCalibrate</name>

            <instance>default</instance>

        </interface>

    </hal>

</manifest>

尝试编译

        在default目录下运行mm进行编译。请记得先在vendor根目录下执行source build/envsetup.sh 和 lunch现在应该能够完成模块编译。

        编译成功后在out/target/product/<project>/vendor/bin/hw能看到编译得到的service可执行文件。

3.3 将service添加进系统

        修改device.mk文件以包含此service。

        我们首先找到hidl版本的编译声明通常位置为device/vendorabcd/<project名或chipset>/device.mk

        例如我找到这样的hidl编译配置

PRODUCT_PACKAGES += vendorabcd.hardware.sensorscalibrate@1.0-service \

                    vendorabcd.hardware.sensorscalibrate@1.0-service.rc \

                    vendorabcd.hardware.sensorscalibrate@1.0 \

                    vendorabcd.hardware.sensorscalibrate-V1.0-java \

                     vendorabcd-hardware-sensorscalibrate.xml

DEVICE_MANIFEST_FILE += device/vendorabcd/chipset/mgvi/manifest_sensorscalibrate.xml

        升级到aidl以后只需配置好service对应的xml即会自动加入编译。

        把以上的内容全部删除。替换为

PRODUCT_PACKAGES += vendorabcd.hardware.sensorscalibrate-service

        可选现在可以全编译一下确认能够正常完成整个系统的全编译。

3章报错速查

FAILED: ninja: '.xml', needed by 'out_hal/(...)/.xml', missing and no known rule to make it

解释ninja错误第2个路径xml中需求了第1个路径的xml但是找不到对应的文件

错误原因可能因为manifest中的旧版本没有删除干净导致编译器寻找已被删除的xml。

解决方法检查 DEVICE_MANIFEST_FILE 中旧版的xml配置并删除干净

ld.lld: error: undefined symbol: >>> the vtable symbol may be undefined because the class is missing its key function

解释clang错误没有找到对应的类因为没有实现对应的虚函数。

错误原因cpp编写有误例如实现函数时未声明namespace SensorsCalibrate::SensorsCal() 错写成 SensorsCal()

解决方法检查cpp文件并修改

4. 确保service开机启动

目标开机时service能够自启动

验证目标开机后执行adb shell service list能看到新的service

        本章将要配置SEpolicy以确保service开机启动。SEpolicy是引入了SELinuxkernel后所需求的一种安全策略。SELinux会默认阻止一些关键操作例如文件操作ioctl等我们需要逐条声明后才能合法进行这些操作。

4.0 开始配置SEpolicy

        在第3章最后我们能编译得到一个新的系统版本。但在这个版本中service不会随开机启动因为我们还没有配置SEpolicy。一种更具有演示性的做法是我们收集log中的拒绝信息再对应配置SEpolicy。然而由于全编译一次的时间成本过高在这里我们先配置完所需的SEpolicy再检查是否能自动启动。

        需要注意的是在配置SEpolicy相关文件时每个文件末尾必须另有一行空白行否则会在编译时遇到无法预知的错误。具体原因我也不太清楚。

4.1 添加新feature目录

        文件vendor/vendorabcd/security/sepolicy_vendor/features/sepolicy_features_vendor.mk 中定义了vendorabcd的vendor相关sepolicy。我们按格式增加一个feature。

        添加如下一行

BOARD_SEPOLICY_DIRS += $(LOCAL_PATH)/sensorscalibrate/vendor

        并在此目录下创建/sensorscalibrate/vendor目录。进入这个新创建的目录。

4.2 创建 hal_sensorscalibrate_default.te

        创建一个文件名为hal_sensorscalibrate_default.te内容如下

type hal_sensorscalibrate_default, domain;

type hal_sensorscalibrate_default_exec, exec_type, vendor_file_type, file_type;

init_daemon_domain(hal_sensorscalibrate_default)

        其中的init_daemon_domain是一段可以自动帮助我们完成与init相关的policy声明。这段宏的括号中的输入x应为一个domain即本文件在第一行定义并有名为x_exec的对象被定义为一个executable在第二行定义。第一行和第二行满足了init_daemon_domain对输入的需求。

        我们现在还没有把 hal_sensorscalibrate_default_exec 与实际文件相绑定。于是另创建一个文件名为file_contexts。

4.3 创建 file_contexts

        file_contexts负责声明实际文件为某个SEpolicy中的对象。

        我们将手机中service可执行文件的路径声明为hal_sensorscalibrate_default_exec

        创建一个文件名为file_contexts内容如下

/(vendor|system/vendor)/bin/hw/vendorabcd\.hardware\.sensorscalibrate-service                   u:object_r:hal_sensorscalibrate_default_exec:s0

4.1 无法启动时的排查方法

1. 确认service本身可正常运行

        我们首先尝试手动启动服务以收集相关log。

        在adb shell内切换到su用户。将SEpolicy调整到宽容模式放行未声明的操作。

su root

setenforce 0

getenforce  #检查是否打开宽容模式输出Permissive为宽容模式

        启动服务

/vendor/bin/hw/vendorabcd.hardware.sensorscalibrate-service

        检查服务是否正常启动。不要关闭前一个终端窗口另开一个窗口在adb shell中执行

service list | grep sensorscalibrate

        有如下输出说明启动成功

159     vendorabcd.hardware.sensorscalibrate.ISensorsCalibrate/default: [vendorabcd.hardware.sensorscalibrate.ISensorsCalibrate]

        如果方括号[ ]内没有内容可能是未成功打开宽容模式。

2. 检查启动阶段的log

        dmesg是linux提供的内核log工具与系统启动相关的log在其中有记录。

        打开终端进入sudo模式收集本次启动的dmesg

adb root

adb shell dmesg > dmesg.txt

        如果看到类似于以下的dmesg内容说明系统启动时由于SEpolicy阻拦service启动失败

[   10.220035] init: init 27: [10038][0]Could not start service 'vendor.sensorscalibrate-hal' as part of class 'hal': File /vendor/bin/hw/vendorabcd.hardware.sensorscalibrate-service(labeled "u:object_r:vendor_file:s0") has incorrect label or no domain transition from u:r:init:s0 to another SELinux domain defined. Have you configured your service correctly?

3 查看系统运行阶段的log

        在宽容模式下系统不会阻止未声明的操作但仍记录这些操作的拒绝记录。我们可以通过拒绝记录来添加对应的声明。

        在adb shell中执行

logcat | grep sensorscalibrate

        若看到有如下log记录了被拒绝的的操作

11-10 16:29:41.311   633   633 E SELinux : avc:  denied  { find } for pid=3223 uid=2000 name=vendorabcd.hardware.sensorscalibrate.ISensorsCalibrate/default scontext=u:r:shell:s0 tcontext=u:object_r:default_android_service:s0 tclass=service_manager permissive=1

#这个log的意思是我试图从shell启动service但是失败了

        log的格式解释如下

avc: denied  { 操作权限  }  for pid=7201  comm=“进程名”  scontext=u:r:源类型:s0  tcontext=u:r:目标类型:s0  tclass=访问类别  permissive=0

        修改步骤

        找相应的“源类型.te ”文件

        按如下格式在该文件中添加

        allow  源类型 目标类型:访问类别 {权限}

        allow vendorabcd_app hal_sensorscalibrate_default:binder {call};​​​​​​​

5. java层调用service含sepolicy配置

        后面写不动了先到这里吧。

        在msi镜像中也要定义同样的aidl接口这样才能进行aidl通信。文件内容使用和vendor中完全相同即可。

推荐阅读

sepolicy进阶小记 - LibXZR 的小本本 解释了许多关键的sepolicy宏很有帮助

AIDL for HALs - Code Inside Out 一个AIDL for HAL全流程的文档比较细

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

“HAL: 将 HIDL 接口改造为 Stable AIDL” 的相关文章