安卓支持RISC-V架构的技术剖析

简介: 本文主要以RISC-V开发板上安卓的实现过程为切入点,讨论了在安卓上添加新的指令架构(ISA)和板级平台支持的各个阶段,概述了每个阶段针对架构需要添加哪些支持,涉及开发过程中一些常见的问题和注意点。

引言

本文主要以RISC-V开发板上安卓的实现过程为切入点,讨论了在安卓上添加新的指令架构(ISA)和板级平台支持的各个阶段,概述了每个阶段针对架构需要添加哪些支持,涉及开发过程中一些常见的问题和注意点;可以作为安卓指令架构支持和板级开发的参考。本文内容主要作为概述,其中细节较多的部分将会在其他文章展开讨论。

为什么要做安卓的RISC-V支持

处理器指令架构在数十年前就开始百花齐放,GCC支持的指令架构数达50+个之多,registry@sco.com注册的EM架构数达252个之多。这些指令架构通常由各家芯片厂商或研究机构独立发起,彼此间相对独立,都需要投入大量人力进行软硬件支撑。出于“Instruction Sets Want to be Free”这一愿景,RISC-V作为一个开源、通用、稳定、简洁、独立的指令架构被提出,目标是让各种规模、微结构、软件栈的计算系统都能基于一种统一的指令架构有效工作。自 2011年推出以来RISC-V迅速地普及,其软件生态也逐步完善;包括GCC/Bintuils工具链、Glibc库、Linux内核等一系列基础设施得到了支持并upstream至开源主枝,Fedora、Debian、openSUSE、Gentoo等一众发行版官方支持了RISC-V架构,Go、OpenJDK、Free Pascal、Rust、Node.js等等高级语言编译/运行环境都支持了RISC-V的后端支持。然而RISC-V在Android生态软件支持上仍有较大的空缺,基于RISC-V架构支持了Android为后续移动/智能终端产品基于RISC-V架构的处理器落地提供了一种较低成本的可能性;现有上层应用不需要较大的改动就可以平滑的移动到使用自由ISA、自由SoC、自由软件的RISC-V平台上。

RISC-V ISA的安卓软件栈支持

安卓软件栈主要包括系统内核、硬件抽象、运行时、框架层、应用五个层次的近千个软件包。其中作为基础的Linux内核、GCC工具链、Clang/LLVM工具链已经支持了RISC-V架构;因此对的主要支持工作集中于RISC-V ISA的编译框架支持、Bionic C库的ISA支持、ART JAVA运行时的ISA支持、RVB-ICE开发板板级的驱动对接、OPENGL的对接、Chromium webview浏览器几个部分;其他依赖包括NDK、VNDK、emulator、unwind解析库、编解码库等等。本文后续将从开发顺序为叙事线索,对上述指令架构需要支持的模块进行介绍。


1.png

如何支持

以下将分五个阶段对安卓的RISC-V ISA支持和RVB-ICE开发板上的板级支持进行概要说明:

Step 1. 准备预编译工程

安卓源代码树包含一个prebuilts目录,里面存放了包括host工具、开发套件、模拟器、二进制的abi描述文件几类预编译工程。使用预编译工程在减少总体编译量、提升二进制兼容性、使模块划分更清晰的同时也带来了更多的架构支持工作量:不尽相同的编译框架、完全独立的编译脚本、单独的ISA的编译支持。以下将对各个预编译工程逐个进行介绍:

工具链

安卓的最新源码已经完全使用Clang来做系统的整体构建,但仍使用libgcc相关的函数库,也会使用-fuse-ld=bfd,-no-integrated-as之类的选项来调用GCC的汇编器,连接器。因此添加RISC-V ISA支持首先需要支持Clang/LLVM和GCC两套工具链。Clang/LLVM工程可以通过以下命令拉取:

repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b llvm-toolchain
repo sync

该工程中需要为RISC-V添加工具前缀、架构配置、运行时库相关的支持;并通过build.py脚本进行构建:

cd toolchain/llvm_android
./build.py

按照以下流程完成工具的生成:

2.png

玄铁910特有的扩展指令优化则可以通过在toolchain/llvm-project/llvm/lib/Target/RISCV下额外添加指令和寄存器tablegen相关描述,使安卓整体工程能得到玄铁910扩展指令的加速。 GCC工具链则可以通过RISC-V官方开源的构建工程生成:

git clone https://github.com/riscv/riscv-gnu-toolchain.git
git submodule update --init --recursive
修改target triplets
./configure --prefix=/opt/riscv
make linux

NDK/VNDK

在拥有两套预编译工具链之后即可着手NDK, VNDK两套开发套件的生成。NDK是一套包含了众多平台库用于C/C++程序开发工具套件,包含C/C++源码、mk描述的原生工程;安卓内部的许多模块都依赖NDK,如system、frameworks路径下各类的原生程序;可以通过ndk-build或gradle编译出适配各个平台兼容API版本的原生执行程序:

foo@bar:[hello]$ ~/android-ndk/android-ndk-r20/ndk-build
Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-16.
[arm64-v8a] Compile        : hello-android <= hello.c
[arm64-v8a] Executable     : hello-android
...
[riscv64] Compile        : hello-android <= hello.c
[riscv64] Executable     : hello-android
[riscv64] Install        : hello-android => libs/riscv64/hello-android
...

NDK构建工程可以通过以下命令拉取:

repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b ndk-r20
repo sync

其中rxx为版本号需要与系统版本要求的最小API相适应。该工程中需要为RISC-V添加工具主要需要添加版本、位宽、路径相关的配置支持;并通过checkbuild.py脚本进行构建:

./ndk/checkbuild.py

VNDK则是用于让供应商实现其 HAL 对接的一套原生库的集合,包括框架共享库和SP-HAL两个部分。可以让系统在升级的时候其供应商分区保持不变,避免API/ABI变化所引发的问题;VNDK可以基于安卓的主工程使用以下命令生成:

make vndk dist

Linux内核

Linux内核在安卓中通常也通过预编译方式存放,通用模拟器使用的内核镜像存放于prebuilts/qemu-kernel而设备板级通常存放于device目录;一般来说开发板会使用Image二进制或gz文件,模拟器可以使用elf文件以方便调试 :

foo@bar:~$ cd aosp
foo@bar:[aosp]$ file prebuilts/qemu-kernel/riscv64/ranchu/kernel-qemu
prebuilts/qemu-kernel/riscv64/ranchu/kernel-qemu: ELF 64-bit LSB executable, UCB RISC-V, version 1 (SYSV), statically linked, BuildID[sha1]=60388b123f1c60053407fd899f9acceed43ac267, with debug_info, not stripped
foo@bar:[aosp]$ file device/linaro/hikey-kernel/Image.gz-dtb-hikey960-4.19
device/linaro/hikey-kernel/Image.gz-dtb-hikey960-4.19: gzip compressed data, max compression, from Unix, original size 7301488

Linux内核工程可以通过以下命令拉取:

repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/kernel/manifest -b common-android-5.4-stable
repo sync

RISC-V的Linux内核在4.15版本就被upstream至kernel.org主枝,因此只需要添加相关配置文件就可以使用脚本构建安卓的内核镜像:

New file: common/arch/riscv/configs/gki_defconfig
New file: common/build.config.gki.riscv64
New file: common/build.config.riscv64
构建内核:
BUILD_CONFIG=common/build.config.gki.riscv64 build/build.sh

模拟器相关的驱动通常以goldfish开头,在内核中已经有实现;其中goldfish_pipe则较为泛用,会被用于主机通信、adb、网络、opengl渲染等等功能,其他驱动都对应一个专门的外设功能。模拟器中的虚拟平台的设备树要配置与内核compatible一致的,否则会导致设备缺失、协议不兼容等相关问题。

foo@bar: [common]$ find drivers -name goldfish*.c
drivers/input/keyboard/goldfish_events.c                     #虚拟触摸输入
drivers/platform/goldfish/goldfish_pipe_base.c               #主机通信接口
drivers/platform/goldfish/goldfish_pipe_v1.c                 #主机通信接口
drivers/platform/goldfish/goldfish_pipe_v2.c                 #主机通信接口
drivers/power/supply/goldfish_battery.c                      #虚拟电量设备
drivers/staging/goldfish/goldfish_audio.c                    #虚拟音频输出
drivers/staging/goldfish/goldfish_sync.c
drivers/tty/goldfish.c                                         #虚拟终端输出
drivers/video/fbdev/goldfishfb.c                             #虚拟FrameBuffer显示

RVB-ICE开发板板级则需要将所有未upstream至内核官方源码树的第三方设备驱动与内核代码整合或使用ko方式进行模块编译。这些驱动通常包括存储、显示、触控、传感器、USB、蓝牙、摄像、定位、音频、硬件codec等等,需要在后续服务调试过程中与HAL进行对接,向上层应用提供基础服务。此外开发过程中也会发现一些模块缺失或者兼容性问题,需要在后续调试过程中不断的进行调整和适配。

模拟器

安卓的模拟器基于QEMU实现,通过一个中间glue层进行对接,最外层实现了emulator封装;提供了虚拟设备管理、镜像指定、snapst缓存、gpu加速、摄像头模拟、网络映射等功能。还可以针对需要编译成TV、电话、穿戴、平板、车载等不同配置。以通过以下命令拉取:

repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b emu-master-dev
repo sync

emulator提供的大部分特性都与架构无关,而external/qemu/target/riscv目录下已经支持了RISC-V相关的tcg指令反应和C的help函数,因此RISC-V相关支持只需要添加cmake编译支持、emulator的架构字串、和external/qemu/hw/riscv/下的goldfish虚拟设备即可。虚拟设备文件主要包括内存配置、设备树创建、中断控制器初始化、虚拟设备创建、固件加载几个部分;其中需要注意设备数和设备创建和内核配置的一致性,不然很容易出现设备匹配问题:

...
static const struct MemmapEntry {   //内存分区
...
static void riscv_ranchu_board_init(MachineState *machine)
{
...
    /* 初始化内存分区 */
    memory_region_init_ram(main_mem, NULL, "riscv_ranchu_board.ram",
                          machine->ram_size, &error_fatal);
...
    /* 创建设备树 */
    fdt = create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
...
   /* 创建goldfish设备 */
   create_device(s, fdt, RANCHU_GOLDFISH_FB);
...
   /* 加载opensbi  */
       riscv_load_firmware (machine->firmware, memmap[RANCHU_DRAM].base, NULL);
...

之后使用脚本构建模拟器包:

cd external/qemu/
./android/rebuild.sh

其他

其他预编译工程还包括clang-tool、gdbserver等等。clang-tool包含ABI比较、版本管理相关工具,由prebuilts/clang-tools/build-prebuilts.sh脚本生成。而gdbserver则由binutils-gdb工程静态预编译生成,可以用于原生C/C++程序和ART底层执行环境的调试。

Step 2. 编译框架和构建支持

安卓 7.0版本之后代码构建通过Blueprint和Soong实现。bp文件作用取代过去的mk文件包含编译目标模块的名称、代码、链接库、编译链接选项等参数。而Soong(会调用Blueprint相关工具)则类似于make命令的展开部分负责将bp转换为ninja文件,ninja文件主要保存于out/soong/build.ninja,通过调用ninja -f build.ninja命令就能根据规则完成各个模块的编译。

3.png

除了编译框架之外,RISC-V架构支持还包括原生C/C++程序、Java运行时两个部分的支持。原生C/C++程序支持主要包括Bionic、opengl、protobuf、libunwindstack等模块,还包括一些可以进行汇编优化的加解密、音视频、AI模块;JAVA运行时则集中于ART目录实现。

编译框架支持

安卓的编译框架支持主要位于build目录下,又分为make和soong两部分。soong部分针对架构主要要维护函数库路径、编译链接选项、ABI、架构名称字串等相关内容。make部分则主要包括架构名称匹配、工具链的路径和参数和通用板级相关的配置。预编译工程中的VNDK、SDK都对编译框架有依赖,因此在生成这两个预编译工程前要求编译框架和bionic都得到了相关支持。为RISC-V添加虚拟机平台主要需要添加以下文件:

1. core/combo/TARGET_linux-riscv64.mk               //编译ABI,toc生成规矩,链接目标配置
2. core/combo/arch/riscv64/riscv64.mk               //用于指定平台相关的额外编译选项,如指令集
3. target/board/generic_riscv64/BoardConfig.mk    //模拟器平台定义,引用一些通用外设或镜像配置
4. target/board/generic_riscv64/device.mk           //定义JAVA虚拟机运行参数等一些设备配置
5. target/board/generic_riscv64/system.prop          //定义系统运行环境的prop变量
6. target/product/aosp_riscv64.mk                    //定义产品名称,依赖包列表等配置
7.

RVB-ICE开发板的板级平台支持与通用模拟器配置略有不同,存放于device下的对应板级目录内,主要包括:

Android.bp/Android.mk                      //设备顶层编译脚本
AndroidProducts.mk                      //产品选单配置
BoardConfigCommon.mk                     //板级配置,包含架构、功能开关、recovery等相关配置
common.kl                                  //按键触摸映射
device-common.mk                           //定义依赖包列表等配置
[device_name].mk                           //定义产品名称和相关字串
[device_name]/BoardConfig.mk               //板级配置,包括名称、启动参数、镜像大小等等
[device_name]/fstab.[device_name]          //产品的挂载定义
[device_name]/device-[device_name].mk      //定义设备文件安装规则
init.*.rc                                  //设备特有的初始化脚本
manifest.xml                               //支持的hal接口定义
system.prop                                //定义系统运行环境的prop变量

其他部分主要为一些特性支持和HAL对接会随设备的复杂度增加而增加:

audio                                     //音频设备hal对接
bluetooth                                 //蓝牙设备hal对接
gralloc                                   //图形内存管理对接
gpu                                       //gpu加速的hal对接
power                                     //功耗管理的hal对接
overlay                                   //源代码配置覆盖
recovery                                  //恢复分区支持
sensorhal                                 //传感器hal对接
sepolicy                                  //设备的安全规则
vndk                                      //vndk的构建工程
...

Bionic支持

Bionic是Android的C函数库;区别于glibc会提供ISO,POSIX,UNIX,XOPEN,XPG多套接口标准支持,被用与不同的类UNIX系统进行对接;bionic只需要实现与linux内核相关对接,主要覆盖ISO和POSIX相关接口。除了标准C库、线程库以外,还提供了浮点数学库、动态链接器和部分Android特有的接口(如systrace、scudo、property等)。 对于RISC-V ISA支持来说,Bionic中主要实现以下几部分内容:

libc/SECCOMP_*.TXT                  //seccomp黑白名单
libc/SYSCALLS.TXT                     //系统调用列表
libc/arch-common/bionic/crtbegin.c    //c函数跳转入库
libc/arch-riscv64/bionic/*            //汇编实现的通用系统接口
libc/arch-riscv64/generic/*           //mem/str类函数汇编优化
libc/arch-riscv64/syscalls/*          //系统调用接口
libc/include/bits/elf_riscv64.h       //重定位类型声明
libc/include/bits/fenv_riscv64.h      //浮点异常定义
libc/include/sys/ucontext.h           //上下文保存结构定义
libc/kernel/uapi/asm-riscv/*          //内核头文件
libc/libc.map.txt                     //符号输出控制文件
libc/private/bionic_asm_riscv64.h     //架构相关对齐,layout定义
libc/private/*tls*                    //tls相关处理
libc/seccomp/*                        //安全接口对接声明
libm/riscv64/fenv.c                   //浮点控制接口实现
linker/*                              //重定位相关实现
tests/prebuilt-elf-files/riscv64/*    //动态加载测试用例
tools/versioner/*                     //版本工具支持

libc部分主要对常用内存操作函数、内核提供的系统调用、数据结构等内容进行了封装向用户态程序提供了标准化的接口;Bionic的线程库也位于libc中实现,大部分线程接口如创建、等待、取消都为公共实现;架构相关的主要为tls部分,需要为RISC-V定义相关layout,各个数据结构(tp、tcb、dtv)的获取等等。 动态链接程序使用库函数依赖于链接器相关的支持,链接器负责将dso加载至任意内存地址,并对需要重定位的指令进行修改使其能正常的执行跳转集地址获取指令;Bionic中的链接器公共代码实现了8种常用重定位的定义,一般架构只需要将对应重定位序号进行对接即可。

其他原生程序支持

其他原生程序支持还包括程序堆栈回溯支持、OPENGL支持、汇编加速优化、protobuf支持等等。 安卓中为程序错误提供完善的dump和调用栈回溯功能,其中native层的堆栈回溯主要基于的libunwindstack实现。RISC-V相关支持主要需要添加ptrace调用的寄存器上下文的格式,栈帧的寄存器排布和elf信息解析相关功能。 OPENGL的支持则包括GL接口entry桩点,GPU设备对接两个部分。GL接口entry桩点,包含一段架构特有的汇编入口实现,负责加载opengl tls数据结构和准备接口参数。GPU设备对接通常需要和IP供应商对接,使用对应sysroot的工具链生成依赖的图形库文件以保证加载时的依赖关系正确性;此外还需要对gralloc(内存管理),compositor(合成单元),drm(图形渲染框架)进行对接,使上层程序可以正常的调用GPU底层接口。 对于安卓这种业务覆盖密集运算、音视频、加解密、3d渲染、AI的系统来说,如何使用适当的软件编码来尽可能的发挥硬件性能尤为重要。如bionic的内存/字符串操作/浮点运算、boringssl的大数模乘、编解码的乘累加,NN引擎的数组向量化运算都可以针对指令架构进行优化;使用大位宽、可非对齐访问、复合功能、向量化的扩展指令进行优化往往能给热点程序提供数倍到数十倍的性能提升。

ART支持

Android应用程序是基于JAVA语言编译生成的dalvik字节码程序。由于linux系统无法直接执行dalvik字节码的应用程序,Android系统上集成了一个可以运行dalvik字节码程序的虚拟机。虚拟机的作用在于将dalvik字节码的功能通过系统提供的库、CPU的指令,完成对应字节码的功能。 从Android-5开始,DVM被ART取代(但是很多执行文件的名字还是叫做delvik),ART引入了AOT技术,在应用安装或者手机充电的时候,ART会利用dex2oat工具编译应用代码,将其编译为与目标机器CPU想匹配的代码。其过程可以用下图描述。


4.png


从上图ART虚拟机的运行流程中,主要有三部分内容是移植RISC-V的关键:

  1. AOT编译器:图中.oat文件的生成工具,oat文件包含可执行二进制码的文件。AOT编译器作用是将dex字节码编译成oat文件,缺省配置下,在编译时或者安装时,会调用dex2oat来完成,
  2. JIT编译器:图中紫色部分,dex字节码运行过程中,ART记录执行的方法是否是热点方法,并生成profiling信息。JIT编译器的作用根据profiling信息对热点方法进行编译。
  3. Interpreter:dex字节码解释器,用于执行Android的dex字节码

此外,无论Interpreter还是编译器都会用到汇编器以及反汇编器。 接下来的内容,我们就从汇编器,解释器,编译器几个方面对移植工作做个简单的介绍

汇编器

汇编器的功能是将编译的指令转换成机器码,是ART中编译器部分的基础部件。在移植到RISC-V体系架构过程中,完成RISC-V所有指令集的汇编功能。

解释器

解释器的作用就是解释执行dex字节码。RISC-V指令架构支持过程中,该部分工作集中在:

  • dex字节码翻译成RISC-V指令
  • c++/java现场转换的context的保存和恢复

编译器

AOT编译器和JIT编译器在ART中使用的是同一套编译框架,复用同一套实现代码。两个编译器的目的都是为了将dex字节码编译成可执行二进制码。


5.png


从上图可以看到,编译器经过优化后,得到ART HInstruction,再由体系结构相关的后端处理,生成对应体系结构的指令。上图中标注为黄色部分为RISC-V体系结构主要完成工作:

  • 优化遍:指令简化(Instruction Simplifier), Intrinsic,Vector
  • RISC-V后端:指令生成(Code Gen),寄存器分配

Step 3. 原生小系统启动

在mksh命令行和toybox小工具集能够正常基于安卓生成之后即可开始进行原生程序相关的调试。本阶段需要在完成系统分区和镜像烧写,boot的引导, 内核的启动,文件系统的加载,运行各类初始化rc脚本,启用selinux相关环境,启动rc脚本注册的各种服务,初始化命令行,最后进入循环等待各类事务的处理。


6.png


内核启动

在系统启动调试初始阶段通常会使用gdb加载linux内核(打包自制的ramdisk)方式调试基础的c程序运行。内核在kernel_init中调用prepare_namespace完成ramdisk挂载后就会通过ramdisk_execute_command运行init进程,init进程一般使用静态编译,因此可以直接使用gdb调试从load_elf_binary接口向下通过异常处理函数进入用户态,观察程序出错点,此时出现的问题通常只涉及crtbegin入口的参数和跳转处理,系统调用的传参和返回,以及init-array是否被正常调用。当走通静态程序执行后即可在init中调用动态编译的程序,主要调试动态库加载,符号重定位等相关内容。当以上过程都顺利走通,就表示原生程序运行已经基本走通,可以开始进一步正规的init启动过程调试了。


7.png

系统初始化

安卓的初始化函数位于system/core/init下,分为first_stage_init.cpp和init.cpp两个阶段。第一阶段主要负责节点的创建和部分文件系统的挂载(要求boot,system,vender,data等分区在开发板上已经按照分区表进行行了烧写,RVB-ICE开发板使用的是GPT),log系统的初始化,一些基础环境变量的设置;之后会调用selinux_setup加载预编译的规则和上下文文件,为各个文件节点配置安全属性,在调试时selinux进行修改通常会带来不少额外的工作量,因此在开发过程中通常在系统的bootargs中添加permissive选项关闭相应校验功能;当selinux完成加载之后会调用第二阶段的初始化,本阶段主要包括property的设置、二阶段的安全上下文配置、ActionManager的初始化、Keychord的队列维护、命令行的启动和原生服务的启动。至此系统的初始化已经完成大半,原生部分也仅剩余服务部分需要进行调试了。


8.png


在第二阶段的init loop循环中会维护包含SurfaceFlinger、netd、vold、apex、ashmem、installd、media等模块的调试。这些服务通过/root或/system/etc/init下的rc文件进行维护,在特定扳机被触发或property被设置后启动。这些服务模块大多依赖板级平台上的HAL对接,device下需要实现包括存储、wifi、gpu、音频的接口支持,并通过相应用例以保证服务执行运行。安卓启动动画也会在本阶段SurfaceFlinger和bootanimation走通后正常显示。本阶段主要使用adb+gdbserver配合logcat吐出的日志信息进行调试。

Step 4. Zygote与Java服务

zygote启动

zygote进程是所有java服务的父进程,它是由init进程从配置⽂件中获取app_process程序的启动⽅式(包括参数)并启动的;会进⼊⽂件 frameworks/base/core/jni/AndroidRuntime.cpp,然后进⼊此⽂件中的函数:startVm正式启动ART虚拟机,然后调用通过native方法"com.android.internal.os.ZygoteInit",启动Zygote进程,进入Zygote的JAVA环境。


9.png


JAVA服务启动

Java服务启动位于frameworks/base/services/java/com/android/server/SystemServer.java,分BootstrapServices、CoreServices、OtherServices三个阶段启动各类Java服务,服务使用高级语言编写与指令架构基本无关;但在系统层面会关心底层与HAL对接的硬件模块实现是否完全,对应系统服务deamon是否在正常的提供服务,系统运行的速度是太慢触发了TIMEOUT机制,JAVA虚拟机执行出错是否为ART实现问题等等。在开发过程中常常有许多模块由于架构支持不完全等原因被暂时绕过,后续服务启动就会发现执行出错,此时通常打开对应服务的log后通过logcat就能看到对应错误原因,再针对性的调试对应模块依赖就能解决大多数的服务问题。在模拟器调试中由于qemu执行指令较慢会出现大量的服务启动超时问题,大部分的超时问题可以通过log打印查看,再改长对应服务延时即可解决。上层java应用逻辑也可以使用JDB,单步java代码查看程序路径进行调试。

Step 5. launcher桌面显示

在原生程序和Java服务都调试稳定的理想状况下,系统自然可以启动到桌面。然而实际的系统调试往往并没有那么顺利,常见问题现象通常有启动动画循环播放、模块缺失、系统服务执行奔溃等等。这种情况下通常会其他架构平台的运行状况进行对比,依次确认SurfaceFlinger、WindowsManager相关服务是否正常的初始化;Wallpaper、systemUI、Launcher三个app的程序逻辑是否符合预期;配合原生程序和java服务调试过程中相关的手段,就能解决大部分问题了。此外使用系统单元测试用例保证每个模块工作逻辑正常也会对整体系统调试提供很大的帮助。


10.png

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
20天前
|
Kubernetes Cloud Native 微服务
探索云原生技术:容器化与微服务架构的融合之旅
本文将带领读者深入了解云原生技术的核心概念,特别是容器化和微服务架构如何相辅相成,共同构建现代软件系统。我们将通过实际代码示例,探讨如何在云平台上部署和管理微服务,以及如何使用容器编排工具来自动化这一过程。文章旨在为开发者和技术决策者提供实用的指导,帮助他们在云原生时代中更好地设计、部署和维护应用。
|
1月前
|
安全 Android开发 iOS开发
深入探索Android与iOS的差异:从系统架构到用户体验
在当今的智能手机市场中,Android和iOS无疑是最受欢迎的两大操作系统。本文旨在探讨这两个平台之间的主要差异,包括它们的系统架构、开发环境、安全性、以及用户体验等方面。通过对比分析,我们可以更好地理解为何不同的用户群体可能会偏好其中一个平台,以及这些偏好背后的技术原因。
|
13天前
|
监控 安全 API
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
本文详细介绍了PaliGemma2模型的微调流程及其在目标检测任务中的应用。PaliGemma2通过整合SigLIP-So400m视觉编码器与Gemma 2系列语言模型,实现了多模态数据的高效处理。文章涵盖了开发环境构建、数据集预处理、模型初始化与配置、数据加载系统实现、模型微调、推理与评估系统以及性能分析与优化策略等内容。特别强调了计算资源优化、训练过程监控和自动化优化流程的重要性,为机器学习工程师和研究人员提供了系统化的技术方案。
133 77
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
|
24天前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
19天前
|
运维 Cloud Native 持续交付
云原生技术深度探索:重塑现代IT架构的无形之力####
本文深入剖析了云原生技术的核心概念、关键技术组件及其对现代IT架构变革的深远影响。通过实例解析,揭示云原生如何促进企业实现敏捷开发、弹性伸缩与成本优化,为数字化转型提供强有力的技术支撑。不同于传统综述,本摘要直接聚焦于云原生技术的价值本质,旨在为读者构建一个宏观且具体的技术蓝图。 ####
|
25天前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统架构差异及其对开发者的影响
本文旨在通过对比分析iOS和Android两大移动操作系统的系统架构,探讨它们在设计理念、技术实现及开发者生态方面的差异。不同于常规摘要仅概述内容要点,本摘要将简要触及核心议题,为读者提供对两大平台架构特点的宏观理解,铺垫
|
23天前
|
网络协议 Linux Android开发
深入探索Android系统架构与性能优化
本文旨在为读者提供一个全面的视角,以理解Android系统的架构及其关键组件。我们将探讨Android的发展历程、核心特性以及如何通过有效的策略来提升应用的性能和用户体验。本文不包含常规的技术细节,而是聚焦于系统架构层面的深入分析,以及针对开发者的实际优化建议。
39 1
|
26天前
|
Cloud Native 持续交付 云计算
云原生技术在现代IT架构中的转型力量####
本文深入剖析了云原生技术的精髓,探讨其在现代IT架构转型中的关键作用与实践路径。通过具体案例分析,展示了云原生如何赋能企业实现更高效的资源利用、更快的迭代速度以及更强的系统稳定性,为读者提供了一套可借鉴的实施框架与策略。 ####
24 0
|
26天前
|
运维 Kubernetes Docker
深入理解容器化技术及其在微服务架构中的应用
深入理解容器化技术及其在微服务架构中的应用
56 1
|
28天前
|
IDE 安全 Android开发
深入探索Android与iOS操作系统的架构差异
本文旨在对比分析Android和iOS两大主流移动操作系统在架构设计上的根本差异。通过详细解读两者的系统架构、开发环境、以及安全性等方面,揭示它们各自的特点及优势,为开发者选择合适的平台提供参考。

热门文章

最新文章