smali简介及反编译应用
最后更新于:2022-04-01 23:27:36
安卓下app应用举例
最后更新于:2022-04-01 23:27:33
mxnet
最后更新于:2022-04-01 23:27:31
讯飞SDK
最后更新于:2022-04-01 23:27:29
opencv
最后更新于:2022-04-01 23:27:27
linux下app应用举例
最后更新于:2022-04-01 23:27:24
camdriod 走读
最后更新于:2022-04-01 23:27:22
# camdriod编译过程走读
## camdroid编译
~~~
source build/envsetup.sh #导入环境变量设置,如下面的这些命令
lunch #选择平台型号,在build/envsetup.sh,包含了device/softwinner/common/vendorsetup.sh
mklichee #编译BootLoader和内核,模块
extract-bsp #拷贝前面的结果
make -j12 #编译camdroid
pack #打包镜像
~~~
## lichee编译
mklichee在device/softwinner/common/vendorsetup.sh里:
~~~
function mklichee()
{
mksetting
mk_info "build lichee ..."
mkbr && mkkernel
# mkbr && mkkernel && mkuboot
[ $? -ne 0 ] && return 1
return 0
}
~~~
### mksetting打印配置信息
~~~
function mksetting()
{
printf "\n"
printf "mkscript current setting:\n"
printf " Chip: ${LICHEE_CHIP}\n"
printf " Platform: ${LICHEE_PLATFORM}\n"
printf " Board: ${LICHEE_BOARD}\n"
printf " Output Dir: ${LICHEE_PLAT_OUT}\n"
printf "\n"
}
~~~
实际打印结果:
> mkscript current setting:
> Chip: sun8iw8p1
> Platform:
> Board:
> Output Dir: /home/zp/develop/lichee_git/lichee_zero/camdroid/../lichee/out/sun8iw8p1/linux/common
### mkbr编译buildroot
~~~
function mkbr()
{
mk_info "build buildroot ..."
local build_script
build_script="scripts/build.sh"
LICHEE_PLATFORM="linux"
(cd ${LICHEE_BR_DIR} && [ -x ${build_script} ] && ./${build_script} "buildroot" ${LICHEE_PLATFORM} ${LICHEE_CHIP})
[ $? -ne 0 ] && mk_error "build buildroot Failed" && return 1
mk_info "build buildroot OK."
}
~~~
执行结果:
~~~
INFO: build buildroot ...
external toolchain has been installed
INFO: build buildroot OK.
~~~
> export LICHEE_BR_DIR=${LICHEE_DIR}/buildroot
所以先进入lichee/buildroot,
-x表示进入跟踪模式,执行scripts/build.sh,这里是导入了一些路径变量
~~~
EXTERNAL_DIR=${LICHEE_BR_DIR}/external-packages
DESTDIR=${LICHEE_BR_DIR}/images
STAGING_DIR=${LICHEE_BR_OUT}/staging
INCDIR=${STAGING_DIR}/usr/include
TARGET_DIR=${LICHEE_BR_OUT}/target
TARGET_SYSROOT_OPT="--sysroot=${STAGING_DIR}"
~~~
然后执行`./${build_script} "buildroot" ${LICHEE_PLATFORM} ${LICHEE_CHIP}`
也就是:`./scripts/build.sh "buildroot" linux sun8iw8p1`
解析命令里没有对后面的参数进行解析。。
~~~
case "$1" in
clean)
rm -rf ${LICHEE_BR_OUT}
;;
*)
if [ "x${LICHEE_PLATFORM}" = "xlinux" ] ; then #根本没有对这个赋值
build_buildroot
export PATH=${LICHEE_BR_OUT}/external-toolchain/bin:$PATH
build_external
else
build_toolchain
fi
;;
esac
~~~
这里执行了后面的else,也就是build_toolchain(其实是解压外部工具链)
~~~
build_toolchain()
{
local tooldir="${LICHEE_BR_OUT}/external-toolchain"
mkdir -p ${tooldir} #out/sun8iw8p1/linux/common/buildroot/external-toolchain
if [ -f ${tooldir}/.installed ] ; then
printf "external toolchain has been installed\n"
else
printf "installing external toolchain\n"
printf "please wait for a few minutes ...\n"
tar --strip-components=1 \
-jxf ${LICHEE_BR_DIR}/dl/gcc-linaro.tar.bz2 \
-C ${tooldir}
[ $? -eq 0 ] && touch ${tooldir}/.installed
fi
export PATH=${tooldir}/bin:${PATH}
}
~~~
简单地说就是把buildroot/dl/gcc-linaro.tar.bz2 解压到out/sun8iw8p1/linux/common/buildroot/external-toolchain
另一路选择执行的两个函数:
~~~
build_buildroot() //编译buildroot
{
if [ ! -f ${LICHEE_BR_OUT}/.config ] ; then #如果没有配置过,则使用默认配置
printf "\nUsing default config ...\n\n"
make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} ${LICHEE_BR_DEFCONF}
fi
make O=${LICHEE_BR_OUT} -C ${LICHEE_BR_DIR} LICHEE_GEN_ROOTFS=n \
BR2_JLEVEL=${LICHEE_JLEVEL}
}
build_external() //external-packages,指buildroot里的所有外部包
{
for dir in ${EXTERNAL_DIR}/* ; do
if [ -f ${dir}/Makefile ]; then
BUILD_COMMAND="make -C ${dir} ${BUILD_OPTIONS} all"
eval $BUILD_COMMAND
BUILD_COMMAND="make -C ${dir} ${BUILD_OPTIONS} install"
eval $BUILD_COMMAND
fi
done
}
~~~
即执行了:`make O=out/sun8iw8p1/linux/common/buildroot -C ./ LICHEE_GEN_ROOTFS=n BR2_JLEVEL=${LICHEE_JLEVEL}`
即编译br目录,但不生成rootfs
### mkkernel编译内核
~~~
function mkkernel()
{
local platformdef=$tdevice
if [ ! -n $tdevice ]; then
echo "Please lunch device"
return 1
fi
echo "Make the kernel"
echo "platformdef="${platformdef}
(cd ${LICHEE_KERN_DIR}/; ./build.sh -p ${platformdef})
[ $? -ne 0 ] && mk_error "build mkkernel fail" && return 1
echo "Make the kernel finish"
return 0
}
~~~
执行显示结果:
~~~
Make the kernel
platformdef=tiger-cdr
~~~
即执行了:Cd lichee/linux3.4; ./build.sh -p tiger-cdr
~~~
#这里首先导入了PLATFORM=tiger-cdr
while getopts hp:m: OPTION
do
case $OPTION in
h) show_help
;;
p) PLATFORM=$OPTARG
;;
m) MODULE=$OPTARG
;;
*) show_help
;;
esac
done
#没有指定platform则退出
if [ -z "$PLATFORM" ]; then
show_help
exit 1
fi
#没有指定模块则默认编译所有
if [ -z "$MODULE" ]; then
MODULE="all"
fi
#执行scripts/build_tiger-cdr.sh
if [ -x ./scripts/build_${PLATFORM}.sh ]; then
./scripts/build_${PLATFORM}.sh $MODULE
else
printf "\nERROR: Invalid Platform\nonly sun6i sun6i_fiber or sun6i_dragonboard sopport\n"
show_help
exit 1
fi
~~~
对应目录里脚本为:
~~~
LICHEE_ROOT=`(cd ${LICHEE_KDIR}/..; pwd)`
export PATH=${LICHEE_ROOT}/out/sun8iw8p1/linux/common/buildroot/external-toolchain/bin:${LICHEE_ROOT}/tools/pack/pctools/linux/android:$PATH
case "$1" in
kernel)
build_kernel
;;
modules)
build_modules
;;
clean)
clean_kernel
clean_modules
;;
*)
build_kernel
build_modules
# build_ramfs #这里可以生成boot.img
# gen_output
echo -e "\n\033[0;31;1m${LICHEE_CHIP} compile Kernel successful\033[0m\n\n"
;;
esac
~~~
总之就是默认编译了内核和模块。。
可以看到build_kernel其实编译了uImage和modules,并把bImage和zImage拷到了output目录
把ko文件拷到了lichee/linux-3.4/output/lib/modules/3.4.39下
~~~
build_kernel()
{
echo "Building kernel"
cd ${LICHEE_KDIR}
rm -rf output/
echo "${LICHEE_MOD_DIR}"
mkdir -p ${LICHEE_MOD_DIR}
# echo "build_kernel LICHEE_KERN_DEFCONF" ${LICHEE_KERN_DEFCONF}
# We need to copy rootfs files to compile kernel for linux image
# cp -f rootfs.cpio.gz output/
if [ ! -f .config ] ; then
# printf "\n\033[0;31;1mUsing default config ${LICHEE_KERN_DEFCONF} ...\033[0m\n\n"
printf "\n\033[0;31;1mUsing default config sun8iw8p1smp_tiger_cdr_defconfig ...\033[0m\n\n"
# cp arch/arm/configs/${LICHEE_KERN_DEFCONF} .config
cp arch/arm/configs/sun8iw8p1smp_tiger_cdr_defconfig .config
fi
make ARCH=arm CROSS_COMPILE=${CROSS_COMPILE} -j${LICHEE_JLEVEL} uImage modules
update_kern_ver
#The Image is origin binary from vmlinux.
cp -vf arch/arm/boot/Image output/bImage
cp -vf arch/arm/boot/[zu]Image output/
cp .config output/
tar -jcf output/vmlinux.tar.bz2 vmlinux
if [ ! -f ./drivers/arisc/binary/arisc ]; then
echo "arisc" > ./drivers/arisc/binary/arisc
fi
cp ./drivers/arisc/binary/arisc output/
for file in $(find drivers sound crypto block fs security net -name "*.ko"); do
cp $file ${LICHEE_MOD_DIR}
done
cp -f Module.symvers ${LICHEE_MOD_DIR}
}
~~~
build_modules部分就没做事了
### mkuboot编译uboot
(这部分代码没有放出)
~~~
function mkuboot()
{
(cd ${LICHEE_UBOOT_DIR}; ./build.sh -p sun8iw8p1_nor)
[ $? -ne 0 ] && echo "build u-boot Failed" && return 1
(cd ${LICHEE_UBOOT_DIR}; ./build.sh -p sun8iw8p1)
[ $? -ne 0 ] && echo "build u-boot Failed" && return 1
return 0
}
~~~
## extract-bsp
拷贝zimage和modules
~~~
CURDIR=$PWD
cd $DEVICE
#extract kernel
if [ -f kernel ]; then
rm kernel
fi
cp -rf $LICHEE_KERN_OUTDIR/zImage kernel
echo "$DEVICE/zImage copied!"
#extract linux modules
if [ -d modules ]; then
rm -rf modules
fi
mkdir -p modules/modules
cp -rf $LINUXOUT_MODULE_DIR modules/modules
echo "$DEVICE/modules copied!"
chmod 0755 modules/modules/*
cd $CURDIR
~~~
## pack打包镜像
~~~
function pack()
{
if [ "-d" == $1 ]; then
echo "pack card"
pack_card
else
echo "pack_normal"
pack_normal
fi
return 0
}
~~~
~~~
function pack_normal()
{
local platformdef=$tdevice
echo "Pack to image........." ${platformdef}
export CAMLINUX_IMAGE_OUT="$CAMLINUX_BUILD_TOP/out/target/product/${platformdef}"
if [ "tiger-ipc" == ${platformdef} ]; then
echo "copy tiger-ipc uboot bin files"
cp -rf ${LICHEE_TOOLS_DIR}/pack/chips/sun8iw8p1/configs/tiger-ipc/bin ${LICHEE_TOOLS_DIR}/pack/chips/sun8iw8p1/
fi
(cd ${LICHEE_TOOLS_DIR}/pack; ./pack -c sun8iw8p1 -p camdroid -b ${platformdef} )
[ $? -ne 0 ] && echo "pack Failed" && return 0
return 0
}
function pack_card()
{
...
(cd ${LICHEE_TOOLS_DIR}/pack; ./pack -c sun8iw8p1 -p camdroid -b ${platformdef} -d card0 )
...
}
~~~
打包过程:
./pack -c sun8iw8p1 -p camdroid -b ${platformdef}
~~~
do_prepare
do_common
echo "CAMLINUX_IMAGE_OUT="${CAMLINUX_IMAGE_OUT}
do_pack_${PACK_PLATFORM}
do_finish
~~~
### do_prepare
~~~
tools_file_list=(
common/tools/split_xxxx.fex
chips/${PACK_CHIP}/tools/split_xxxx.fex
common/tools/usbtool_test.fex
chips/${PACK_CHIP}/tools/usbtool_test.fex
common/tools/cardscript.fex
chips/${PACK_CHIP}/tools/cardscript.fex
common/tools/cardtool.fex
chips/${PACK_CHIP}/tools/cardtool.fex
common/tools/usbtool.fex
chips/${PACK_CHIP}/tools/usbtool.fex
common/tools/aultls32.fex
chips/${PACK_CHIP}/tools/aultls32.fex
common/tools/aultools.fex
chips/${PACK_CHIP}/tools/aultools.fex
)
configs_file_list=(
common/toc/toc1.fex
common/toc/toc0.fex
common/imagecfg/image_linux.cfg
common/partition/sys_partition_dump.fex
common/partition/sys_partition_private.fex
chips/${PACK_CHIP}/configs/default/*
chips/${PACK_CHIP}/configs/${PACK_BOARD}/*.fex
chips/${PACK_CHIP}/configs/${PACK_BOARD}/*.cfg
)
boot_resource_list=(
chips/${PACK_CHIP}/boot-resource/boot-resource:out/
chips/${PACK_CHIP}/boot-resource/boot-resource.ini:out/
chips/${PACK_CHIP}/configs/${PACK_BOARD}/bootlogo.bmp:out/boot-resource/
)
boot_file_list=(
chips/${PACK_CHIP}/bin/boot0_nand_${PACK_CHIP}.bin:out/boot0_nand.fex
chips/${PACK_CHIP}/bin/boot0_sdcard_${PACK_CHIP}.bin:out/boot0_sdcard.fex
chips/${PACK_CHIP}/bin/boot0_spinor_${PACK_CHIP}.bin:out/boot0_spinor.fex
chips/${PACK_CHIP}/bin/fes1_${PACK_CHIP}.bin:out/fes1.fex
chips/${PACK_CHIP}/bin/u-boot-${PACK_CHIP}.bin:out/u-boot.fex
chips/${PACK_CHIP}/bin/u-boot-spinor-${PACK_CHIP}.bin:out/u-boot-spinor.fex
)
boot_file_secure=(
chips/${PACK_CHIP}/bin/semelis.bin:out/semelis.bin
chips/${PACK_CHIP}/bin/sboot_${PACK_CHIP}.bin:out/sboot.bin
)
function do_prepare()
{
...
# Cleanup
rm -rf out/
mkdir -p out/
printf "copying tools file\n"
for file in ${tools_file_list[@]} ; do
cp -f $file out/ 2> /dev/null
done
...
#拷贝各种fex到out下,包含开机画面等
~~~
### do_common
转换格式,通过fex更新boot
~~~
function do_common()
{
cd out/
busybox unix2dos sys_config.fex
busybox unix2dos sys_partition.fex
script sys_config.fex > /dev/null
script sys_partition.fex > /dev/null
cp -f sys_config.bin config.fex
if [ "x${PACK_PLATFORM}" = "xdragonboard" ] ; then
busybox dos2unix test_config.fex
cp test_config.fex boot-resource/
busybox unix2dos test_config.fex
script test_config.fex > /dev/null
cp test_config.bin boot-resource/
fi
# Those files for SpiNor. We will try to find sys_partition_nor.fex
if [ -f sys_partition_nor.fex -o \
-f sys_partition_nor_${PACK_PLATFORM}.fex ]; then
mv -f sys_partition_nor_${PACK_PLATFORM}.fex \
sys_partition_nor.fex >/dev/null 2>&1
# Here, will create sys_partition_nor.bin
busybox unix2dos sys_partition_nor.fex
script sys_partition_nor.fex > /dev/null
update_boot0 boot0_spinor.fex sys_config.bin SDMMC_CARD > /dev/null
update_uboot u-boot-spinor.fex sys_config.bin >/dev/null
fi
# Those files for Nand or Card
update_boot0 boot0_nand.fex sys_config.bin NAND > /dev/null
update_boot0 boot0_sdcard.fex sys_config.bin SDMMC_CARD > /dev/null
update_uboot u-boot.fex sys_config.bin > /dev/null
update_fes1 fes1.fex sys_config.bin > /dev/null
fsbuild boot-resource.ini split_xxxx.fex > /dev/null
if [ "x${PACK_FUNC}" = "xprvt" ] ; then
u_boot_env_gen env_burn.cfg env.fex > /dev/null
else
u_boot_env_gen env.cfg env.fex > /dev/null
fi
if [ -f "$LICHEE_OUT/arisc" ]; then
ln -s $LICHEE_OUT/arisc arisc.fex
fi
}
~~~
### do_pack_${PACK_PLATFORM}
~~~
function do_pack_android()
{
printf "packing for android\n"
if [ -z "${ANDROID_IMAGE_OUT}" ] ; then
pack_error "please specify ANDROID_IMAGE_OUT env"
exit 1
fi
ln -s ${ANDROID_IMAGE_OUT}/boot.img boot.fex
ln -s ${ANDROID_IMAGE_OUT}/system.img system.fex
ln -s ${ANDROID_IMAGE_OUT}/recovery.img recovery.fex
if [ -f ${ANDROID_IMAGE_OUT}/userdata.img ] ; then
ln -s ${ANDROID_IMAGE_OUT}/userdata.img userdata.fex
fi
if [ "x${PACK_SIG}" = "xsig" ] ; then
echo "signature sunxi mbr"
signature sunxi_mbr.fex dlinfo.fex
echo "signature over"
elif [ "x${PACK_SIG}" = "xsecure" ] ; then
do_signature
else
echo "normal"
fi
}
function do_pack_camdroid()
{
printf "packing for camdroid\n"
if [ -z "${CAMLINUX_IMAGE_OUT}" ] ; then
pack_error "please specify CAMLINUX_IMAGE_OUT env"
exit 1
fi
ln -s ${CAMLINUX_IMAGE_OUT}/boot.img boot.fex
ln -s ${CAMLINUX_IMAGE_OUT}/system.img rootfs.fex #使用前面打包的system.img作为根文件系统
}
function do_pack_dragonboard()
{
printf "packing for dragonboard\n"
ln -s ${LICHEE_OUT}/boot.img boot.fex
ln -s ${LICHEE_OUT}/rootfs.ext4 rootfs.fex
}
function do_pack_linux()
{
printf "packing for linux\n"
#输出目录是linux-3.4/output/
ln -s ${LICHEE_OUT}/vmlinux.tar.bz2 vmlinux.fex
ln -s ${LICHEE_OUT}/boot.img boot.fex #
ln -s ${LICHEE_OUT}/rootfs.ext4 rootfs.fex
if [ "x${PACK_SIG}" = "xsecure" ] ; then
do_signature
else
echo "normal"
fi
}
~~~
### do_finish
~~~
function do_finish()
{
# Yeah, it should contain all files into full_img.fex for spinor
# Because, as usually, spinor image size is very small.
# If fail to create full_img.fex, we should fake it empty.
# WTF, it is so ugly! It must be sunxi_mbr.fex, not sunxi_mbr_xxx.fex
# Check whether sys_partition_nor.bin is exist, and create sunxi_mbr.fex
# for Nor.
if [ -f sys_partition_nor.bin ]; then
mv -f sys_partition.bin sys_partition.bin_back
cp -f sys_partition_nor.bin sys_partition.bin
update_mbr sys_partition.bin 1 > /dev/null
merge_package full_img.fex boot0_spinor.fex \
u-boot-spinor.fex sunxi_mbr.fex sys_partition.bin
mv -f sys_partition.bin_back sys_partition.bin
fi
if [ ! -f full_img.fex ]; then
echo "full_img.fex is empty" > full_img.fex
fi
update_mbr sys_partition_nor.bin 1 > /dev/null
dragon image.cfg sys_partition_nor.fex
if [ -e ${IMG_NAME} ]; then
mv ${IMG_NAME} ../${IMG_NAME}
echo '----------image is at----------'
echo -e '\033[0;31;1m'
echo ${ROOT_DIR}/${IMG_NAME}
echo -e '\033[0m'
fi
cd ..
printf "pack finish\n"
}
~~~
## 打包完成后的布局
~~~
Device Boot Start End Blocks Id System
/dev/sdf1 56992 1939454 941231+ b W95 FAT32
/dev/sdf2 * 40992 46111 2560 6 FAT16
/dev/sdf3 1 56992 28496 85 Linux extended
/dev/sdf5 46112 55199 4544 83 Linux
/dev/sdf6 55200 56223 512 83 Linux
/dev/sdf7 56224 56479 128 83 Linux
/dev/sdf8 56480 56735 128 83 Linux
/dev/sdf9 56736 56863 64 83 Linux
/dev/sdf10 56864 56991 64 83 Linux
~~~
配置里的分区表:
~~~
[partition]
name = boot
size = 5120
downloadfile = "boot.fex" #内核ramfs
[partition]
name = system
size = 9088
downloadfile = "rootfs.fex" #根文件系统
[partition]
name = cfg
size = 1024
downloadfile = "cfg.fex" #jffs2的cfg,用于保存可变的配置字段
[partition]
name = boot_logo
size = 256
downloadfile = "boot_logo.fex"
[partition]
name = shutdown_logo
size = 256
downloadfile = "shutdown_logo.fex"
[partition]
name = env
size = 128
downloadfile = "env.fex" #uboot启动的环境变量
[partition]
name = private
size = 128
~~~
### cfg.fex的生成
device/softwinner/tiger-cdr/res/make_cfg_fex.sh
~~~
CFG_PATH="/pack/chips/sun8iw8p1/configs/CDR/cfg.fex"
DEST=$LICHEE_TOOLS_DIR$CFG_PATH
echo "./mkfs.jffs2 -d ./data -o cfg.fex"
#-p total size
./mkfs.jffs2 -d ./cfg -p 0x80000 -o cfg.fex
echo "move cfg.fex to $DEST"
mv cfg.fex $DEST
~~~
### boot.fex(boot.img)生成
~~~
INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES)
$(call pretty,"Target boot image: $@")
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE),raw)
~~~
~~~
regen_rootfs_cpio()
{
echo "regenerate rootfs cpio"
cd ${LICHEE_KDIR}/output
echo "###"
if [ -x "../scripts/build_rootfs.sh" ]; then
../scripts/build_rootfs.sh e ./rootfs.cpio.gz > /dev/null
else
echo "No such file: scripts/build_rootfs.sh"
exit 1
fi
echo "###"
mkdir -p ./skel/lib/modules/${KERNEL_VERSION}
echo "###"
if [ -e ${LICHEE_MOD_DIR}/nand.ko ]; then
cp ${LICHEE_MOD_DIR}/nand.ko ./skel/lib/modules/${KERNEL_VERSION}
if [ $? -ne 0 ]; then
echo "copy nand module error: $?"
exit 1
fi
fi
echo "###ttt"
ko_file=`find ./skel/lib/modules/$KERNEL_VERSION/ -name *.ko`
if [ ! -z "$ko_file" ]; then
${STRIP} -d ./skel/lib/modules/$KERNEL_VERSION/*.ko
fi
echo "###ttt"
rm -f rootfs.cpio.gz
../scripts/build_rootfs.sh c rootfs.cpio.gz > /dev/null
rm -rf skel
echo "###ttt"
cd - > /dev/null
}
~~~
TARGET_ROOT_OUT := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_ROOT)
# 修改配置生成linux镜像
由上面的走读可知,需要生成boot分区,linux根文件系统分区,及对应的分区表
内核配置:
linux-3.4/arch/arm/configs/sun8iw8p1smp_defconfig
linux-3.4/arch/arm/configs/sun8iw8p1smp_tiger_cdr_defconfig
配置内核:
make ARCH=arm menuconfig
板级配置和开机logo
ls tools/pack/chips/sun8iw8p1/configs/tiger-cdr/
boot-resource cfg.fex sys_config.fex sys_partition_nor_camdroid.fex
';
Zero Linux系统适配过程记录
最后更新于:2022-04-01 23:27:20
安卓ROM深度定制
最后更新于:2022-04-01 23:27:17
uart适配
最后更新于:2022-04-01 23:27:15
# UART适配
## linux 下适配
使用默认编译的安卓系统,ls /dev可以看到 ttyS0~3
尝试echo 'test' > /dev/ttyS0 可以在串口终端看到test字符,说明uart1就是ttyS0
荔枝派上除了默认的uart1是系统log输出口外,uart0与sdc0复用,不方便使用,就剩uart3可以使用。
linux下使用stty设置串口参数:
`stty -F /dev/ttyS1 ispeed 115200 ospeed 115200`
但是发现对ttyS0之外的串口操作会返回:`stty: /dev/ttyS1: Input/output error`
在linux的驱动目录下找到相关文件:tty/serial/8250_sunxi.c
~~~
struct platform_device sw_uart_dev[] = {
[0] = {.name = "sunxi-uart", .id = 0, .num_resources = ARRAY_SIZE(sw_uart_res[0]), .resource = &sw_uart_res[0][0], .dev = {}},
......
};
static int __init sw_serial_init(void)
{
int ret;
int i;
int used = 0;
char uart_para[16];
memset(sw_serial, 0, sizeof(sw_serial));
uart_used = 0;
for (i=0; iport_no = dev->id;
sport->pdev = dev;
ret = sw_serial_get_config(sport, dev->id);
if (ret) {
UART_MSG(KERN_ERR "Failed to get config information\n");
goto free_dev;
}
ret = sw_serial_get_resource(sport);
if (ret) {
UART_MSG(KERN_ERR "Failed to get resource\n");
goto free_dev;
}
platform_set_drvdata(dev, sport);
sport->port.irq = sport->irq;
sport->port.fifosize= 64;
sport->port.regshift= 2;
sport->port.iotype = UPIO_DWAPB32;
sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
sport->port.uartclk = sport->sclk;
sport->port.pm = sw_serial_pm;
sport->port.dev = &dev->dev;
sport->port.mapbase = sport->mmres->start;
sw_serial[sport->port_no] = serial8250_register_port(&sport->port); //注册端口
UART_MSG("serial probe %d, membase %p irq %d mapbase 0x%08x\n",
dev->id, sport->port.membase, sport->port.irq, sport->port.mapbase);
UART_MSG("sport->pdev is %x \n &sport->pdev is %x",sport->pdev,&sport->pdev);
UART_MSG("pdev.dev is %x \n &pdev.dev is %x",sport->pdev->dev,&sport->pdev->dev);
UART_MSG("dev.dev is %x \n &dev.dev is %x",dev->dev,&dev->dev);
return 0;
free_dev:
kfree(sport);
sport = NULL;
return ret;
}
~~~
.config
~~~
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_SUNXI=y
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
~~~
8250.c
~~~
#define UART_NR CONFIG_SERIAL_8250_NR_UA RTS
static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
int serial8250_register_port(struct uart_port *port)
{
struct uart_8250_port *uart;
int ret = -ENOSPC;
if (port->uartclk == 0)
return -EINVAL;
mutex_lock(&serial_mutex);
uart = serial8250_find_match_or_unused(port);
if (uart) {
uart_remove_one_port(&serial8250_reg, &uart->port);
uart->port.iobase = port->iobase;
uart->port.membase = port->membase;
uart->port.irq = port->irq;
uart->port.irqflags = port->irqflags;
uart->port.uartclk = port->uartclk;
uart->port.fifosize = port->fifosize;
uart->port.regshift = port->regshift;
uart->port.iotype = port->iotype;
uart->port.flags = port->flags | UPF_BOOT_AUTOCONF;
uart->port.mapbase = port->mapbase;
uart->port.private_data = port->private_data;
if (port->dev)
uart->port.dev = port->dev;
if (port->flags & UPF_FIXED_TYPE)
serial8250_init_fixed_type_port(uart, port->type);
set_io_from_upio(&uart->port);
/* Possibly override default I/O functions. */
uart->port.flags = port->flags | UPF_BOOT_AUTOCONF;
uart->port.mapbase = port->mapbase;
uart->port.private_data = port->private_data;
if (port->dev)
uart->port.dev = port->dev;
if (port->flags & UPF_FIXED_TYPE)
serial8250_init_fixed_type_port(uart, port->type);
set_io_from_upio(&uart->port);
/* Possibly override default I/O functions. */
if (port->serial_in)
uart->port.serial_in = port->serial_in;
if (port->serial_out)
uart->port.serial_out = port->serial_out;
/* Possibly override set_termios call */
if (port->set_termios)
uart->port.set_termios = port->set_termios;
if (port->pm)
uart->port.pm = port->pm;
if (serial8250_isa_config != NULL)
serial8250_isa_config(0, &uart->port,
&uart->capabilities);
ret = uart_add_one_port(&serial8250_reg, &uart->port);
if (ret == 0)
ret = uart->port.line;
}
mutex_unlock(&serial_mutex);
return ret;
}
~~~
serial_core.c
~~~
/**
* uart_add_one_port - attach a driver-defined port structure
* @drv: pointer to the uart low level driver structure for this port
* @uport: uart port structure to use for this port.
*
* This allows the driver to register its own uart_port structure
* with the core driver. The main purpose is to allow the low
* level uart drivers to expand uart_port, rather than having yet
* more levels of structures.
*/
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
{
struct uart_state *state;
struct tty_port *port;
int ret = 0;
struct device *tty_dev;
BUG_ON(in_interrupt());
if (uport->line >= drv->nr)
return -EINVAL;
state = drv->state + uport->line;
port = &state->port;
mutex_lock(&port_mutex);
mutex_lock(&port->mutex);
if (state->uart_port) {
ret = -EINVAL;
goto out;
}
state->uart_port = uport;
state->pm_state = -1;
uport->cons = drv->cons;
uport->state = state;
/*
* If this port is a console, then the spinlock is already
* initialised.
*/
if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
spin_lock_init(&uport->lock);
lockdep_set_class(&uport->lock, &port_lock_key);
}
uart_configure_port(drv, state, uport);
/*
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters.
*/
tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev); //最终注册设备
if (likely(!IS_ERR(tty_dev))) {
device_init_wakeup(tty_dev, 1);
device_set_wakeup_enable(tty_dev, 0);
} else
printk(KERN_ERR "Cannot register tty device on line %d\n",
uport->line);
/*
* Ensure UPF_DEAD is not set.
*/
uport->flags &= ~UPF_DEAD;
out:
mutex_unlock(&port->mutex);
mutex_unlock(&port_mutex);
return ret;
}
~~~
tty_io.c
~~~
struct device *tty_register_device(struct tty_driver *driver, unsigned index,
struct device *device)
{
char name[64];
dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
if (index >= driver->num) {
printk(KERN_ERR "Attempt to register invalid tty line number "
" (%d).\n", index);
return ERR_PTR(-EINVAL);
}
if (driver->type == TTY_DRIVER_TYPE_PTY)
pty_line_name(driver, index, name);
else
tty_line_name(driver, index, name);
return device_create(tty_class, device, dev, NULL, name);
}
EXPORT_SYMBOL(tty_register_device);
static void tty_line_name(struct tty_driver *driver, int index, char *p)
{
sprintf(p, "%s%d", driver->name, index + driver->name_base); //最终的ttySx
}
~~~
大致的驱动加载过程就是上面这样
下面看下log信息:
~~~
[ 0.158533] [uart]: used uart info.: 0x06
[ 0.158563] [uart]: this coming sw_serial_probe
[ 0.288179] [uart]: serial probe 1, membase (null) irq 2 mapbase 0x01c28400
[ 0.295378] [uart]: sport->pdev is c08c4a08
[ 0.295383] &sport->pdev is df04c2c8[uart]: pdev.dev is c08c4ad0
[ 0.303155] &pdev.dev is c08c5680[uart]: dev.dev is c08c4ad0
[ 0.309079] &dev.dev is c08c5680[uart]: this coming sw_serial_probe
[ 0.318097] [uart]: <3>Failed to get config information
[ 0.323344] sunxi-uart: probe of sunxi-uart.2 failed with error -1
~~~
可见uart1和uart3在获取fex时都被识别出来了,uart1成功probe,但是uart3“Failed to get config information”
uart3对应sw_uart_dev[2],即
~~~
ret = sw_serial_get_config(sport, dev->id);
if (ret) {
UART_MSG(KERN_ERR "Failed to get config information\n");
goto free_dev;
}
static int sw_serial_get_config(struct sw_serial_port *sport, u32 uart_id)
{
char uart_para[16] = {0};
int ret;
sprintf(uart_para, "uart_para%d", uart_id);
ret = script_parser_fetch(uart_para, "uart_port", &sport->port_no, sizeof(int));
if (ret)
return -1;
if (sport->port_no != uart_id)
return -1;
ret = script_parser_fetch(uart_para, "uart_type", &sport->pin_num, sizeof(int));
if (ret)
return -1;
return 0;
}
~~~
查看可知fex里的uart_port和uart_parax必须一一对应,所以就是fex里之前写错了,改正回来
这时查看ttyS1参数就有了:
~~~
busybox stty -F /dev/ttyS1
speed 9600 baud;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ;
eol2 = ; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 1; time = 0;
-brkint -imaxbel
~~~
设置下波特率,并测试
~~~
busybox stty -F /dev/ttyS1 ispeed 115200 ospeed 115200
echo 'test' > /dev/ttyS1
~~~
成功在uart3上收到数据~
';
pm解析
最后更新于:2022-04-01 23:27:13
usb适配
最后更新于:2022-04-01 23:27:11
# usb适配简记
##usb调试信息太多,删减之
~~~
[ 232.061924] [sw_hcd]: sw_hcd_urb_dequeue, sw_hcd(df8a28ec, 0x0, 0x3f),urb(dbd34f00, 1514, 0), dev = 3, ep = 2, dir = in
[ 232.071179] sw_hcd_cleanup_urb: qh(0xd0df6e40,0x2,0x2), urb(0xdbd34f00,1514,0), ep(0xdf8a2a00,3,0xd0df6e40,0x (null))
~~~
出处在
~~~
./linux-3.0/drivers/usb/sun5i_usb/hcd/core/sw_hcd_host.c: DMSG_INFO("[sw_hcd]: sw_hcd_urb_dequeue, sw_hcd(%p, 0x%d, 0x%x),"
./linux-3.0/drivers/usb/sun5i_usb/hcd/core/sw_hcd_host.c: DMSG_INFO("sw_hcd_cleanup_urb: qh(0x%p,0x%x,0x%x), urb(0x%p,%d,%d), ep(0x%p,%d,0x%p,0x%p)\n",
~~~
修改linux-3.0/drivers/usb/sun5i_usb/include/sw_usb_debug.h
~~~
/* 普通信息打印 */
#if 0
#define DMSG_INFO DMSG_PRINT
#else
#define DMSG_INFO(...)
#endif
~~~
##3g网卡适配
安卓下开启3g网卡主要步骤是
1. 在驱动中勾选usb串口,pppd等
2. 调试通过usb_modeswitch, 模式切换后自动或者手动出现3个ttyUSBx设备
3. evdo脚本拨号
4.
###在内核配置里开启串口驱动,pppd驱动等
`Device Drivers -> USB support -> USB Serial Converter support USB driver for GSM and CDMA modems`
~~~
<*> PPP (point-to-point protocol) support
[*] PPP multilink support (EXPERIMENTAL)
[*] PPP filtering
<*> PPP support for async serial ports
<*> PPP support for sync tty ports
<*> PPP Deflate compression
<*> PPP BSD-Compress compression
<*> PPP MPPE compression (encryption) (EXPERIMENTAL)
<*> PPP over Ethernet (EXPERIMENTAL)
<*> PPP over IPv4 (PPTP) (EXPERIMENTAL)
<*> PPP over L2TP (EXPERIMENTAL)
<*> PPP on L2TP Access Concentrator
<*> PPP on PPTP Network Server
~~~
###先在电脑上试着驱动3g网卡 :
插上后查看内核信息:
~~~
[ 8497.458906] usb 2-2.1: new full-speed USB device number 12 using uhci_hcd
[ 8497.726318] usb 2-2.1: New USB device found, idVendor=1d09, idProduct=1000
[ 8497.726323] usb 2-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 8497.726325] usb 2-2.1: Product: USB MMC Storage
[ 8497.726327] usb 2-2.1: Manufacturer: Qualcomm, Incorporated
[ 8497.726329] usb 2-2.1: SerialNumber: 000000000002
[ 8497.729026] usb-storage 2-2.1:1.0: USB Mass Storage device detected
[ 8497.729192] scsi host43: usb-storage 2-2.1:1.0
[ 8498.732291] scsi 43:0:0:0: Direct-Access Qualcomm MMC Storage 2.31 PQ: 0 ANSI: 2
[ 8498.738204] scsi 43:0:0:1: CD-ROM Qualcomm MMC Storage 2.31 PQ: 0 ANSI: 2
[ 8498.741198] sd 43:0:0:0: Attached scsi generic sg3 type 0
[ 8498.835612] sd 43:0:0:0: [sdb] Attached SCSI removable disk
[ 8500.089041] sr 43:0:0:1: [sr2] scsi3-mmc drive: 357x/308x writer cdda
[ 8500.089184] sr 43:0:0:1: Attached scsi CD-ROM sr2
[ 8500.089287] sr 43:0:0:1: Attached scsi generic sg4 type 5
[ 8500.361385] sr 43:0:0:1: [sr2] CDROM (ioctl) error, command:
[ 8500.361391] Xpwrite, Read disk info 51 00 00 00 00 00 00 00 02 00
[ 8500.361395] sr 43:0:0:1: [sr2] Sense Key : Hardware Error [current]
[ 8500.361397] sr 43:0:0:1: [sr2] Add. Sense: No additional sense information
~~~
lsusb看网卡型号:
> Bus 002 Device 007: ID 1d09:1000 TechFaith Wireless Technology Limited
可以看到被识别成了安装光盘,sr2,手动弹出光盘后就变为正常的设备: eject sr2
//有些网卡需要发送特别的指令,需要使用usb_modeswitch切换模式
> Bus 002 Device 013: ID 1d09:e003 TechFaith Wireless Technology Limited
这就和usb_modeswitch的效果一样
~~~
[ 8662.455084] usb 2-2.1: USB disconnect, device number 12
[ 8666.948103] usb 2-2.1: new full-speed USB device number 13 using uhci_hcd
[ 8667.220302] usb 2-2.1: New USB device found, idVendor=1d09, idProduct=e003
[ 8667.220305] usb 2-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=4
[ 8667.220307] usb 2-2.1: Product: CDMA 1x/EVDO Rev.A Device
[ 8667.220309] usb 2-2.1: Manufacturer: Co.,Ltd
[ 8667.220310] usb 2-2.1: SerialNumber: 000000000002
[ 8667.240512] usb-storage 2-2.1:1.3: USB Mass Storage device detected
[ 8667.246943] scsi host44: usb-storage 2-2.1:1.3
[ 8668.253167] scsi 44:0:0:0: Direct-Access Qualcomm MMC Storage 2.31 PQ: 0 ANSI: 2
[ 8668.255704] sd 44:0:0:0: Attached scsi generic sg3 type 0
[ 8668.271240] sd 44:0:0:0: [sdb] Attached SCSI removable disk
~~~
PID=0x1D09, VID=0xe0003
在drivers/usb/serial/option.c里加入PID,VID(转换后的)
~~~
//发现华为一个型号的PID一样。。
#define HUAWEI_PRODUCT_ET128 0x1D09
#define HUAWEI_VENDOR_ID 0x12D1
//自己加一个吧
595 static const struct usb_device_id option_ids[] = {
596 { USB_DEVICE(0xe0003, 0x1d09) }, //ID 1d09:1000 TechFaith Wireless Technology Limited
~~~
Device Monitoring Studio抓取3G网卡MessageContent
http://blog.chinaunix.net/uid-29764914-id-5181529.html
usb_modeswitch的使用(新版下的规则文件下载)
http://blog.csdn.net/yang1982_0907/article/details/45969179
但是切换后仍然没有ttyUSBx, 需要手工增加:
~~~
modprobe usb_wwan
modprobe option
echo "1d09 e003" > /sys/bus/usb-serial/drivers/option1/new_id
~~~
运行后出现了ttyUSB0~2
可以将它加入到udev规则中,在/lib/udev/rules.d/50-udev-default.rules(也可能再etc目录中)后面添加
ACTION=="add", SUBSYSTEM=="usb",SYSFS{idVendor}=="1d09", SYSFS{idProduct}=="1000",
RUN+="/usr/sbin/usb_modeswitch -c /etc/usb_modeswitch.conf"
RUN+="echo '1d09 e003' > /sys/bus/usb-serial/drivers/option1/new_id"
//安卓下已经自带
~~~
vim /etc/usb_modeswitch.d/1d09_1000
DefaultVendor= 0x1d09
DefaultProduct= 0x1000
TargetVendor= 0x1d09
TargetProduct= 0xe003
StandardEject=1
CheckSuccess= 10 #wait 10s
~~~
然后进行拨号,在/etc/ppp/peers目录下创建新文件evdo:
~~~
mkdir /etc/ppp/peers/
busybox vi /etc/ppp/peers/evdo
~~~
~~~
/dev/ttyUSB0
115200
nodetach
lock
user "ctnet@mycdma.cn"
password "vnet.mobi"
crtscts
show-password
usepeerdns
noauth
noipdefault
novj
novjccomp
noccp
defaultroute
ipcp-accept-local
ipcp-accept-remote
connect '/usr/sbin/chat -s -v -f /etc/ppp/peers/evdo-connect-chat'
#connect '/system/bin/chat -s -v -f /etc/ppp/peers/evdo-connect-chat' #android
~~~
再创建evdo-connect-chat
`busybox vi /etc/ppp/peers/evdo-connect-chat`
~~~
TIMEOUT 2
ABORT 'NO CARRIER'
ABORT 'ERROR'
ABORT 'NO DIALTONE'
ABORT 'BUSY'
ABORT 'NO ANSWER'
"" ATE1
"" "AT+CFUN=1"
OK-AT-OK ATD#777
CONNECT ''
~~~
输入命令pppd call evdo&就可以上网了,断开网络就输入poff。
输出的拨号信息:
~~~
pppd call evdo
timeout set to 2 seconds
abort on (NO CARRIER)
abort on (ERROR)
abort on (NO DIALTONE)
abort on (BUSY)
abort on (NO ANSWER)
send (ATE1^M)
send (AT+CFUN=1^M)
expect (OK)
^M
OK
-- got it
send (ATD#777^M)
expect (CONNECT)
^M
AT+CFUN=1^M^M
OK^M
ATD#777^M^M
CONNECT
-- got it
send (^M)
Serial connection established.
Using interface ppp0
Connect: ppp0 <--> /dev/ttyUSB0
CHAP authentication succeeded: OK
CHAP authentication succeeded
local IP address 10.100.35.16
remote IP address 125.88.103.85
primary DNS address 114.114.114.114
secondary DNS address 223.5.5.5
^CTerminating on signal 2
Connect time 0.2 minutes.
Sent 355 bytes, received 126 bytes.
Connection terminated.
~~~
###安卓上驱动
安卓上串口和dmesg的信息有限,主要看logcat
首次尝试pppd call evdo,log信息如下:
`pppd ( 1230): Can't create lock file /var/lock/LCK..ttyUSB0`
排查发现根本没有/var/lock目录,于是新建/var/run和/var/lock目录
~~~
mkdir /var
mkdir /var/run
mkdir /var/lock
~~~
重新拨号,dmesg提示:
~~~
timeout set to 2 seconds
abort on (NO CARRIER)
abort on (ERROR)
abort on (NO DIALTONE)
abort on (BUSY)
abort on (NO ANSWER)
send (ATE1^M)
send (AT+CFUN=1^M)
expect (OK)
ATE1^M^M
OK
-- got it
send (ATD#777^M)
expect (CONNECT)
^M
AT+CFUN=1^M^M
OK^M
ATD#777^M^M
CONNECT
-- got it
send (^M)
~~~
logcat -v time提示
~~~
01-02 08:01:51.419 I/pppd ( 1195): Serial connection established.
01-02 08:01:51.429 D/pppd ( 1195): using channel 1
01-02 08:01:51.479 I/pppd ( 1195): Using interface ppp0
01-02 08:01:51.479 I/pppd ( 1195): Connect: ppp0 <--> /dev/ttyUSB0
01-02 08:01:52.179 I/pppd ( 1195): CHAP authentication succeeded: OK
01-02 08:01:52.299 I/pppd ( 1195): local IP address 10.100.34.51
01-02 08:01:52.299 I/pppd ( 1195): remote IP address 125.88.103.85
01-02 08:01:52.299 I/pppd ( 1195): primary DNS address 114.114.114.114
01-02 08:01:52.299 I/pppd ( 1195): secondary DNS address 223.5.5.5
~~~
ifconfig可见ppp0设备:
~~~
ppp0 Link encap:Point-to-Point Protocol
inet addr:10.100.46.132 P-t-P:125.88.103.85 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1430 Metric:1
RX packets:3 errors:0 dropped:0 overruns:0 frame:0
TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:54 (54.0 B) TX bytes:54 (54.0 B)
~~~
此时已经可以ping 通114.114.114.114,但无法解析域名
~~~
busybox vi init.sun5i.rc
setprop "net.dns1" "8.8.8.8"
setprop "net.dns2" "8.8.4.4"
~~~
###安卓上3g网卡自动加载总结
0. 切换上网卡状态(/etc/usb_modeswitch.d/1d09_1000自动完成)
1. 创建ttyUSB0等串口
`echo "1d09 e003" > /sys/bus/usb-serial/drivers/option1/new_id`
2. /etc/ppp/peers/evdo /etc/ppp/peers/evdo-connect-chat 拨号脚本(创建一次即可)
3. mkdir /var /var/run /var/lock 创建临时目录
4. pppd call evdo& 拨号上网,并设置dns
0,已经自动完成
1,需要在init.sun5i.rc里加上初始化
~~~
on boot
#echo "1d09 e003" > /sys/bus/usb-serial/drivers/option1/new_id //太早执行无效
exec /system/bin/sh /system/etc/ppp.sh //这里延时到开机执行
~~~
2, 在sdk里加上对应的脚本
相关文件在device/softwinner/common/rild里,需要修改上层的sw-common.mk来拷贝文件到system分区
~~~
PRODUCT_COPY_FILES += \
device/softwinner/common/rild/ip-down:system/etc/ppp/ip-down \
device/softwinner/common/rild/ip-up:system/etc/ppp/ip-up \
device/softwinner/common/rild/call-pppd:system/etc/ppp/call-pppd \
device/softwinner/common/rild/peers/evdo:system/etc/ppp/peers/evdo\
device/softwinner/common/rild/peers/evdo-connect-chat:system/etc/ppp/peers/evdo-connect-chat\
~~~
3, 需要在init.sun5i.rc里加上初始化
~~~
mkdir /var 0770 root system
mount tmpfs none /var mode=0770,uid=0,gid=1000
mkdir /var/run 0750 root system
mkdir /var/lock 0750 root system
~~~
4, 需要在init.sun5i.rc里加上初始化
~~~
service ppp /system/bin/pppd call evdo
user root
group system radio
disabled
oneshot
setprop "net.dns1" "8.8.8.8"
setprop "net.dns2" "8.8.4.4"
~~~
';
wifi适配
最后更新于:2022-04-01 23:27:08
# RTL8723BU wifi模块适配
##linux驱动添加
安卓下使能外设驱动都需要先适配好linux下驱动,所以首先来编译linux驱动模块
1. 拷贝官方驱动(github的资源文件目录下下载)到lichee的linux驱动目录下
~~~
zp@ubuntu:~/develop/a13_android4.1_v1.2/lichee$ ls linux-3.0/drivers/net/wireless/rtl8723bu/
clean core hal ifcfg-wlan0 include Kconfig Makefile os_dep platform runwpa wlan0dhcp
~~~
2. 配置驱动Makefile以及Kconfig,然后在menuconfig里选中刚加入的驱动
`CONFIG_PLATFORM_ARM_SUNxI = y`
`obj-$(CONFIG_RTL8723BU) += rtl8723bu/`
`source "drivers/net/wireless/rtl8723bu/Kconfig"`
` Realtek 8723B USB WiFi`
3. 重新编译lichee,获得内核模块
`./build.sh -p a13_nuclear -k 3.0`
~~~
zp@ubuntu:~/develop/a13_android4.1_v1.2/lichee$ ls out/android/lib/modules/3.0.8+/87*
out/android/lib/modules/3.0.8+/8723bu.ko
~~~
4. 修改wifi驱动,隐藏过多调试信息
前面这样生成的ko带有很多调试信息输出,以至于开启wifi模块时太慢,导致打开wifi超时,所以需要隐藏多余的信息。
编辑linux-3.0/drivers/net/wireless/rtl8723bu/include/autoconf.h,去掉DEBUG的相关宏定义。
##安卓配置文件
1. 修改板级配置文件device/softwinner/nuclear-evb/BoardConfig.mk
~~~
BOARD_WIFI_VENDOR := realtek
ifeq ($(BOARD_WIFI_VENDOR), realtek)
WPA_SUPPLICANT_VERSION := VER_0_8_X
BOARD_WPA_SUPPLICANT_DRIVER := NL80211
BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_rtl
BOARD_HOSTAPD_DRIVER := NL80211
BOARD_HOSTAPD_PRIVATE_LIB := lib_driver_cmd_rtl
SW_BOARD_USR_WIFI := rtl8723bu
BOARD_WLAN_DEVICE := rtl8723bu
endif
~~~
2. 修改init启动脚本init.sun5i.rc
~~~
# 1.1 realtek wifi sta service
service wpa_supplicant /system/bin/wpa_supplicant -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf -e/data/misc/wifi/entropy.bin
class main
socket wpa_wlan0 dgram 660 wifi wifi
disabled
oneshot
# 1.2 realtek wifi sta p2p concurrent service
service p2p_supplicant /system/bin/wpa_supplicant \
-ip2p0 -Dnl80211 -c/data/misc/wifi/p2p_supplicant.conf -e/data/misc/wifi/entropy.bin -N \
-iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf
class main
socket wpa_wlan0 dgram 660 wifi wifi
disabled
oneshot
~~~
3.修改安卓板级mk文件nuclear_evb.mk(蓝牙需要,wifi不用改)
4. 修改安卓hardware相关代码hardware/libhardware_legacy/wifi/wifi.c
~~~
#elif defined RTL_8723BU_WIFI_USED
/* rtl8723bu usb wifi */
#ifndef WIFI_DRIVER_MODULE_PATH
#define WIFI_DRIVER_MODULE_PATH "/system/vendor/modules/8723bu.ko"
#endif
#ifndef WIFI_DRIVER_MODULE_NAME
#define WIFI_DRIVER_MODULE_NAME "8723bu"
#endif
#ifndef WIFI_DRIVER_MODULE_ARG
#define WIFI_DRIVER_MODULE_ARG "ifname=wlan0 if2name=p2p0"
~~~
5. wifi的安卓mk修改
~~~
hardware/libhardware_legacy/wifi/Android.mk
ifeq ($(SW_BOARD_USR_WIFI), rtl8723bu)
LOCAL_CFLAGS += -DRTL_8723BU_WIFI_USED
LOCAL_CFLAGS += -DRTL_WIFI_VENDOR
endif
~~~
6. wpa的安卓mk修改
~~~
external/wpa_supplicant_8/wpa_supplicant/Android.mk
ifeq ($(SW_BOARD_USR_WIFI), rtl8188eu)
L_CFLAGS += -DCONFIG_WFD
endif
~~~
5. 重新编译安卓
实际需要更新的就只有libhardware_legacy.so和8723bu.ko,当然也可以打包整个镜像重新烧写。
以局部更新为例,挂载tf卡的第7分区,拷贝so到lib/libhardware_legacy.so
拷贝ko到vendor/modules
sync后启动即可
';
codec适配及Audio系统解析
最后更新于:2022-04-01 23:27:06
# codec适配及Audio系统解析
##codec适配
启动后耳机及mic无反应,开始绕了个大圈看了遍安卓的Audio系统,结果从最上层查到最底层,发现原因不过是fex没写全而已:
~~~
[audio_para]
audio_used = 1
audio_playback_used = 1
capture_used = 1
audio_lr_change = 0
audio_pa_ctrl = port:PG0<1><0>
~~~
加上audio_pa_ctrl的配置即可,这里使用了空闲引脚PG0,实际上没有接PA,也可以直接改驱动源码来支持不接PA,不过比较麻烦,就直接拿个空闲引脚凑数了。
##Audio系统解析
';
安卓下外设适配及其系统解析
最后更新于:2022-04-01 23:27:04
安卓系统架构解析
最后更新于:2022-04-01 23:27:02
安卓编译系统解析
最后更新于:2022-04-01 23:26:59
#安卓编译简记
qq群里 @随风破浪 编译安卓一星期未果,我之前的开发机上的lichee目录又不小心被覆盖了,所以抽空简单记录下如何在原始sdk的基础上 修改适配,成功编译出可以跑在荔枝派上的安卓系统。
##1. 编译环境准备
### 开发机系统要求
编译安卓需要64位linux系统,推荐**ubuntu 1404**或者**1604**,
开发机至少需要**4GB内存,40GB硬盘**;推荐**8GB内存,100GB硬盘**以上。
以下是开发过程中目录大小示意:
~~~
zp@ubuntu:~/develop$ du -lh --max-depth=1 v1.5.0/
26G v1.5.0/android
6.8G v1.5.0/lichee
33G v1.5.0/
zp@ubuntu:~/develop$ du -lh --max-depth=1 a13_android4.1_v1.2/
5.2G a13_android4.1_v1.2/lichee
23G a13_android4.1_v1.2/android4.1
28G a13_android4.1_v1.2/
~~~
开发机的CPU配置尽量高,笔者12线程并行编译,配以ssd,首次编译需要45分钟
网友双线程编译,耗时4小时左右。
### 开发机软件环境
首先安装开发所需要的软件包和一些库。
下面的一些安装包可能有些过时的,遇到版本问题请自行解决。
在线安装 JDK6.0
~~~
sudo add-apt-repository "deb http://archive.canonical.com/ lucid partner"
sudo add-apt-repository ppa:ferramroberto/java
sudo apt-get update
sudo apt-get install sun-java6-jdk
sudo update-alternatives --c onfig java
~~~
在线安装编译库
~~~
sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev libc6-dev
lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev
g++-multilib mingw32 tofrodos python-markdown libxml2-utils
~~~
### SDK下载
> 链接: http://pan.baidu.com/s/1pLnjfoZ 密码: cvnm
在SDK目录下 下载以下两个文件
~~~
lichee-4.1-v1.2.tar.gz
android4.1-v1.2.tar.gz
~~~
这是安卓4.1的SDK,前面的是4.2的SDK,
> 我手上的4.2 SDK的mali驱动ko和应用层库so版本对不上,换了从4.1里抠出的对应版本的so后,可以勉强启动系统,但是会不定时地出现缓冲队列满的问题导致ANR,所以暂时无法使用
在开发机上新建目录,如a13_android4.1
然后把两个sdk拷入,解压
把lichee对应的目录名改成lichee(即去掉版本号),目录如下所示
~~~
zp@ubuntu:~/develop/a13_android4.1_v1.2$ ls
android4.1 lichee
~~~
##2. lichee编译
lichee是安卓系统的linux内核部分,需要首先编译,进入lichee目录执行:
~~~
./build.sh -p a13_nuclear -k 3.0
./build.sh pack
~~~
### 编译错误解析
编译过程中会出错,每个人由于其开发环境以及执行步骤的不同,错误都可能不同,下面以我编译时遇到的错误为例进行解析
1. mali驱动编译出错
~~~
make: Entering directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali'
/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0
make -C DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump CONFIG=ca8-virtex820-m400-1 BUILD=release KDIR=/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0
make[1]: Entering directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump'
make -C /home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0 M=/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump modules
make[2]: Entering directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0'
CC [M] /home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump/common/ump_kernel_common.o
arm-none-linux-gnueabi-gcc: directory: No such file or directory
arm-none-linux-gnueabi-gcc: directory": No such file or directory
:0:16: warning: missing terminating " character
make[3]: *** [/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump/common/ump_kernel_common.o] Error 1
make[2]: *** [_module_/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump] Error 2
make[2]: Leaving directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0'
make[1]: *** [all] Error 2
make[1]: Leaving directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump'
make: *** [build] Error 2
make: Leaving directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali'
real 2m35.400s
user 15m36.416s
sys 0m35.740s
~~~
进入排除可知是脚本里检查了SVN版本的问题,我们直接忽略SVN版本,将linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump 目录下的SVN_REV直接赋值为0(在Kbuild和Makefile.common中)
重新编译,仍然是类似的错误,只是换了个目录,于是直接在mali驱动目录下全局搜索SVN_REV,将赋值的地方直接改为0
再重新编译成功
~~~
mkdir: created directory ‘/home/zp/develop/a13_android4.1_v1.2/lichee/out’
‘/home/zp/develop/a13_android4.1_v1.2/lichee/u-boot/u-boot.bin’ -> ‘/home/zp/develop/a13_android4.1_v1.2/lichee/out/android/u-boot.bin’
###############################
# compile success #
###############################
real 0m51.177s
user 1m1.324s
sys 0m4.736s
~~~
##3. 安卓编译
进入安卓目录,执行以下命令序列:
~~~
source build/envsetup.sh #导入一些环境变量
lunch #选择板型,直接选择10. nuclear_evb-eng,以后也直接在上面改
extract-bsp #将lichee中编译得到的内核镜像和模块拷贝过来
time make -j12 2>&1 | tee log.txt #编译system.img,这里-j12换成你电脑的线程数(核数*2)。12线程耗时约
pack #打包成刷机镜像
~~~
编译system.img成功的提示:
~~~
Creating filesystem with parameters:
Size: 536870912
Block size: 4096
Blocks per group: 32768
Inodes per group: 8192
Inode size: 256
Journal blocks: 2048
Label:
Blocks: 131072
Block groups: 4
Reserved block group size: 31
Created filesystem with 1443/32768 inodes and 102168/131072 blocks
+ '[' 0 -ne 0 ']'
Running: mkuserimg.sh -s out/target/product/nuclear-evb/system out/target/product/nuclear-evb/obj/PACKAGING/systemimage_intermediates/system.img ext4 system 536870912
Install system fs image: out/target/product/nuclear-evb/system.img
out/target/product/nuclear-evb/system.img+out/target/product/nuclear-evb/obj/PACKAGING/recovery_patch_intermediates/recovery_from_boot.p maxsize=548110464 blocksize=4224 total=412271984 reserve=5537664
real 36m1.948s
user 350m4.772s
sys 14m16.936s
~~~
pack打包成功的提示:
~~~
/home/zp/develop/a13_android4.1_v1.2/lichee/tools/pack/pctools/linux/eDragonEx//home/zp/develop/a13_android4.1_v1.2/lichee/tools/pack/outBuildImg 0
Dragon execute image.cfg SUCCESS !
CPlugin Free lib
CPlugin Free lib
---------image is at-------------
/home/zp/develop/a13_android4.1_v1.2/lichee/tools/pack/sun5i_android_a13-evb.img
~~~
### 编译错误解析
1. 注意如果编译时突然中断,则可能出现文件截断的情况,需要先清空out 下子目录中的的obj目录,才好继续编译
例如下面错误就是:
~~~
target thumb C++: camera. <= device/softwinner/common/hardware/camera/HALCameraFactory.cpp
In file included from device/softwinner/common/hardware/camera/CameraHardwareDevice.h:26:0,
from device/softwinner/common/hardware/camera/HALCameraFactory.cpp:30:
device/softwinner/common/hardware/camera/CameraHardware.h:29:23: fatal error: videodev2.h: No such file or directory
compilation terminated.
make: *** [out/target/product/generic/obj/SHARED_LIBRARIES/camera._intermediates/HALCameraFactory.o] Error 1
make: *** Waiting for unfinished jobs....
~~~
2. 在pack时遇到以下错误(虽然不导致编译失败,但是启动时会造成错误)
~~~
fail:/home/zp/develop/a13_android4.1_v1.2/lichee/tools/pack/out/bootfs/sprite 0
disk : c
CopyRootToFS(/home/zp/develop/a13_android4.1_v1.2/lichee/tools/pack/out/bootfs)
~~~
检查可以发现是lichee/tools/pack/pack中的打包脚本的这句出错:
`fsbuild bootfs.ini split_xxxx.fex`
这个fsbuild在运行时貌似无法打包bootfs的二级目录,不知为何。。有些人却没有反馈有这个问题,应该是个人的环境不同。
由于fsbuild是二进制提供的,只能通过其作用揣测实际功能,经过试验,上面那句可以用以下脚本代替,
基本作用就是构造一个fat文件系统镜像。
~~~
dd if=/dev/zero of=bootfs.fex bs=1M count=12
mkfs.vfat bootfs.fex
sudo mount bootfs.fex /mnt
sudo cp -r bootfs/* /mnt
sync
sudo umount /mnt
cat split_xxxx.fex >> bootfs.fex
~~~
3. 分区大小的问题(虽然不导致编译失败,但是启动时会造成错误)
如果往system.img里加入了太多东西,可能导致超出了默认的分区大小(512M),则需要修改默认分区规划
验证system.img的实际大小:
`simg2img system.img system.bin`
如果生成的system.bin大小刚好是512M,并且可以挂载,那就是正常的。
如果大小超过了512M,或者挂载时出错,那么就需要修正分区配置。
配置文件在lichee/tools/pack/chips/sun5i/configs/android/a13-evb/sys_config.fex
修改大小即可。
~~~
;------------------------------>nandd, android real rootfs
[partition3]
class_name = DISK
name = system
size_hi = 0
size_lo = 524288
user_type = 1
ro = 0
~~~
##4. 镜像下载
前面pack打包完成后,会生成sun5i_android_a13-evb.img,这就是刷机镜像
镜像烧录工具是网盘中的PhoenixCard,打开后选择tf卡对应盘符,以及待烧录镜像,选择**卡启动**,进行烧录
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/77805d12cdca7a2c82220dc65501c9dc_762x500.png)
### 常见烧录错误
1.偶尔会出现'处理出错'的提示,这时候一般只要重新烧录即可
##5. 启动系统的适配过程
通过以上步骤编译的img还是不能在荔枝派上启动的,前面只能算是编译过一遍evb的安卓,需要在荔枝派上启动,还得进行一系列适配工作。
### 第一次启动(boot1跳转失败)
系统默认串口为UART1,接串口查看信息:
~~~
dram size =512
0xffffffff,0xffffffff
super_standby_flag = 0
HELLO! BOOT0 is starting!
boot0 version : 1.5.2
The size of Boot1 is 0x00036000.
Fail in checking boot1.
Ready to disable icache.
Fail in loading Boot1.
Jump to Fel.
~~~
可见DDR已被识别,但是加载boot1失败。
这其中的原因是DDR虽然被识别,但是参数配置错误,导致运行出错,所以我们需要先配置正确的DDR参数。
DDR参数记录在sys_config1.fex中,这里不过多解释sys_config1.fex的字段,直接使用之前在debian中适配好的fex文件覆盖
lichee/tools/pack/chips/sun5i/configs/android/a13-evb/sys_config1.fex
然后重新进行安卓编译过程。
编译完成后,可以直接重新烧写完整镜像,也可以只更新uboot和bootfs,后者需要对编译系统比较了解,在此不详细展开。
重新烧录后,可以看到闪过了两个开机画面,说明已经可以启动到linux内核了。
### 第二次启动(启动介质错误)
按前面修改后,启动会卡在第二张开机画面,查看串口信息:
~~~
[ 16.009615] init: buffer : /dev/block/nande
[ 16.014564] init: do_umount: /data
[ 16.018071] init: do_umount error = Invalid argument
[ 17.390045] usb 2-1: device not accepting address 2, error -110
[ 17.450200] ehci_irq: port change detect
[ 17.454145] ehci_irq: port change detect
[ 21.007468] init: buffer : /dev/block/nandh
[ 21.012161] init: do_umount: /cache
[ 21.015755] init: do_umount error = Invalid argument
[ 21.022007] init: open device error :No such file or directory
[ 31.008863] init: buffer : /dev/block/nandi
[ 31.013556] init: do_umount: /databk
[ 31.017237] init: do_umount error = Invalid argument
[ 31.029268] init: cannot find '/system/bin/sh', disabling 'console'
[ 31.035766] init: cannot find '/system/bin/servicemanager', disabling 'servicemanager'
[ 31.043742] init: cannot find '/system/bin/vold', disabling 'vold'
[ 31.049968] init: cannot find '/system/bin/netd', disabling 'netd'
[ 31.056192] init: cannot find '/system/bin/debuggerd', disabling 'debuggerd'
[ 31.063282] init: cannot find '/system/bin/rild', disabling 'ril-daemon'
[ 31.069987] init: cannot find '/system/bin/surfaceflinger', disabling 'surfaceflinger'
[ 31.077943] init: cannot find '/system/bin/app_process', disabling 'zygote'
[ 31.084939] init: cannot find '/system/bin/drmserver', disabling 'drm'
[ 31.091502] init: cannot find '/system/bin/mediaserver', disabling 'media'
[ 31.098387] init: cannot find '/system/bin/dbus-daemon', disabling 'dbus'
[ 31.105211] init: cannot find '/system/bin/installd', disabling 'installd'
[ 31.112125] init: cannot find '/system/etc/install-recovery.sh', disabling 'flash_recovery'
[ 31.120541] init: cannot find '/system/bin/keystore', disabling 'keystore'
[ 31.127432] init: cannot find '/system/bin/u3gmonitor', disabling 'u3gmonitor'
[ 31.135780] init: cannot find '/system/bin/sh', disabling 'console'
~~~
可见是tf卡启动与nand启动的不同造成linux内核挂载根文件系统出错,所以需要修改开机启动脚本,即 \*.rc文件
device/softwinner/nuclear-evb/init.sun5i.rc
device/softwinner/nuclear-evb/ueventd.sun5i.rc
将其中的nandX按下面对应关系修改
~~~
nanda —— mmcblk0p2
nandb —— mmcblk0p5
nandc —— mmcblk0p6
nandd —— mmcblk0p7
nande —— mmcblk0p8
nandf —— mmcblk0p9
nandg —— mmcblk0p10
nandh —— mmcblk0p11
nandi —— mmcblk0p12
~~~
其中有一句挂载剩余空间的替换也对应替换:
~~~
#format_userdata /dev/block/nandj NUCLEAR
exec /system/bin/busybox mount -t vfat /dev/block/mmcblk0p1 /mnt/sdcard
~~~
再修改vold.fstab,开机挂载方式,前面两行改成以下,即sd卡0作为sdcard,sd卡2作为外置sd卡
~~~
dev_mount sdcard /mnt/sdcard auto /devices/platform/sunxi-mmc.0/mmc_host
dev_mount extsd /mnt/extsd auto /devices/platform/sunxi-mmc.2/mmc_host
~~~
> 如果需要修改成sd卡2启动,则还需要修改uboot代码
> lichee\u-boot\include\configs中sun5i.a13.h文件中的卡启动定义
> `#define CONFIG_MMC_SUNXI_SLOT 2`
最后修改uboot的环境变量env.cfg (lichee/tools/pack/chips/sun5i/configs/android/default/env.cfg)
将mmc作为启动介质
~~~
bootdelay=1
#default bootcmd, will change at runtime according to key press
bootcmd=run setargs_mmc boot_normal#default nand boot
#kernel command arguments
console=ttyS0,115200
nand_root=/dev/system
mmc_root=/dev/mmcblk0p7
init=/init
loglevel=6
#set kernel cmdline if boot.img or recovery.img has no cmdline we will use this
setargs_nand=setenv bootargs console=${console} root=${nand_root} init=${init} loglevel=${loglevel} partitions=${partitions}
setargs_mmc=setenv bootargs console=${console} root=${mmc_root} init=${init} loglevel=${loglevel} partitions=${partitions}
#nand command syntax: sunxi_flash read address partition_name read_bytes
#0x40007800 = 0x40008000(kernel entry) - 0x800(boot.img header 2k)
boot_normal=sunxi_flash read 40007800 boot;boota 40007800
boot_recovery=sunxi_flash read 40007800 recovery;boota 40007800
boot_fastboot=fastboot
#recovery key
recovery_key_value_max=0x13
recovery_key_value_min=0x10
#fastboot key
fastboot_key_value_max=0x8
fastboot_key_value_min=0x2
~~~
修改完成后重新编译下安卓
为了省事,可以不下载整个镜像,只更新boot.fex和env.fex(lichee/tools/pack/out下)
在linux下,使用fdisk -l查看tf卡分区:
~~~
Device Boot Start End Blocks Id System
/dev/sdb1 3448832 15595518 6073343+ b W95 FAT32 //剩余空间作为u盘
/dev/sdb2 * 73728 106495 16384 6 FAT16 //bootfs,含uboot
/dev/sdb3 1 3448832 1724416 85 Linux extended
/dev/sdb5 106496 139263 16384 83 Linux //env.fex
/dev/sdb6 139264 204799 32768 83 Linux //boot.fex,含linux内核及ramdisk
/dev/sdb7 204800 1253375 524288 83 Linux //system分区
/dev/sdb8 1253376 2301951 524288 83 Linux //data分区
/dev/sdb9 2301952 2334719 16384 83 Linux //misc分区
/dev/sdb10 2334720 2400255 32768 83 Linux //recovery分区
/dev/sdb11 2400256 2924543 262144 83 Linux //cache分区
/dev/sdb12 2924544 3448831 262144 83 Linux //databk分区
~~~
所以只需更新两个分区:
~~~
root@ubuntu64:/home/zp# dd if=env.fex of=/dev/sdb5
256+0 records in
256+0 records out
131072 bytes (131 kB) copied, 0.097856 s, 1.3 MB/s
root@ubuntu64:/home/zp# dd if=boot.fex of=/dev/sdb6
19916+0 records in
19916+0 records out
10196992 bytes (10 MB) copied, 8.54376 s, 1.2 MB/s
root@ubuntu64:/home/zp# sync
~~~
更新之后即可成功进入到安卓系统~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/488a185c2d50f3f7447efb621d4d836e_2976x3968.jpg)
虽然此时可以进入系统,但是很多外设不能运行,这些外设的驱动适配见后面的外设适配解析。
';
安卓系统适配全解析
最后更新于:2022-04-01 23:26:57
ubuntu
最后更新于:2022-04-01 23:26:55
debian
最后更新于:2022-04-01 23:26:53