返回顶部
首页 > 资讯 > 移动开发 >ASan和HWAsan在Android中使用
  • 244
分享到

ASan和HWAsan在Android中使用

androidasanhwasan 2023-09-04 08:09:50 244人浏览 八月长安
摘要

1. ASan和HWAsan比较 ASan HWASan 全称 Address Sanitizer Hardware-assisted AddressSanitizer 版本 可以在32位和64位的x86、x86-64上。 从

1. ASan和HWAsan比较

ASan

HWASan

全称

Address Sanitizer

Hardware-assisted AddressSanitizer

版本

可以在32位和64位的x86、x86-64上。

api 27(Android O MR 1)开始,Android NDK 可支持ASAN。

在Android 11 之后的AOSP master中,弃用了arm64 上的平台开发ASan,改为使用HWASan。

只在Android 10 及以上版本有效,且只使用于AArch64硬件平台。

检测bugs

Stack and heap buffer overflow/underflow

Heap use after free

Stack use outside scope

Double free/wild free

Stack and heap buffer overflow/underflow

Heap use after free

Stack use outside scope

Double free/wild free

stack use after return

要求

CPU 开销(~ 2倍)

代码大小开销(50% ~ 2倍)

内存开销(~ 2倍)

CPU 开销(~ 2倍)

代码大小开销(40% ~ 50%)

内存开销(10% ~ 35%)

原理

使用shadow memory(内存的一个区域)内存状态进行标记,如free掉的内存在shadow中标记为0xfd,已经申请的内存,前后存在安全区标记为0xfa

AArch64是64位的架构,一个64bit的指针值,其中真正用于寻址的只有低48位。

AArch64拥有地址标记(Address tagging, or top-byte-ignore)的特性,它表示允许软件使用64bit指针值的高8位开发特定功能。HWASAN用这8bit来存储一块内存区域的标签(tag)。

缺点

1)ASAN的运行是需要消耗memory和CPU资源的,此外它也会增加代码大小。它的性能相比于之前的工具确实有了质的提升,但仍然无法适用于某些压力测试场景,尤其是需要全局打开的时候。这一点在Android上尤为明显,每当我们想要全局打开ASAN调试某些奇葩问题时,系统总会因为负载过重而跑不起来;

2)对于 free 的内存标记存在隔离时间,即 free 的区域一段时间后重新分配其他所有者,此时原持有者访问不会报错;

3)对应flow的安全区总归有大小,如果踩踏过了安全区,同样不会报错;

1)可移植性差,只用于64位平台;

2)需要对linux Kernel做一些改动以支持工具

3)对于所有错误的检测将有一定概率false negative(漏掉一些真实的错误),概率为1/256。原因是tag的生成只能从256(2的8次方)个数中选一个,因此不同地址的tag将有可能相同

优点

比较ASan:

1)不再需要安全区来检测buffer overflow,既极大地降低了工具对于内存的消耗,也不会出现ASAN中某些overflow检测不到的情况;

2)不再需要隔离区来检测UseAfterFree,因此不会出现ASAN中某些UseAfterFree检测不到的情况

2. ASan 编译

2.1 整体编译

m -j16SANITIZE_TARGET=address m -j16

注意,这里需要两次编译。第一次是为了在 /system/lib 中编译常规库,第二次编译是为了在 /system/lib/asan 中进行 ASan 插桩。 

需要刷新system、vendor、system分区,因为上述第 2 步编译ASAN库在/data/asan目录下。

2.2 单独编译

Android.mkLOCAL_SANITIZE := address Android.bpsanitize: { address: true }

2.2.1 编译共享库

LOCAL_SANITIZE:=addressLOCAL_MODULE_RELATIVE_PATH := asan

这样一来,系统会将库放到 /system/lib/asan 中而非 /system/lib 中。但是需要指定库的路径方便链接:

LD_LIBRARY_PATH=/system/lib/asan或setenv LD_LIBRARY_PATH /system/lib/asan

通过 /proc/PID/maps 验证使用的库是否来自 /system/lib/asan(如果此库存在),如果不是,可能需要停用 selinux:

adb rootadb shell setenforce 0# restart the process with adb shell kill $PID# if it is a system service, or may be adb shell stop; adb shell start.

2.3 无法使用ASan构建

有些目标无法使用ASan 构建:

  • 静态关联的可执行文件
  • LOCA_CLANG:=false 目标
  • 不会针对 SANITIZE_TARGET=address进行ASan 操作的LOCAL_SANITIZE:=false 的目标

在 SANITIZE_TARGET build 中,系统会跳过此类可执行文件,且会将第一个make 调用中构建的版本留在 /system/bin 中。

3. HWASan 编译

3.1 整体编译

export SANITIZE_TARGET=hwaddreSSM -j16

与ASan 不同,HWASan 无需构建两次,只需增量构建,没有特殊的刷写指令,不需要擦除,支持静态可执行文件,并且可以跳过除 libc 之外的任何库的排错。

通过环境变量 SANITIZE_TARGET 指定排错(sanitizer)。

3.2 单独编译bin/lib

在编译脚本中增加如下参数即可

Android.mkLOCAL_SANITIZE:= hwaddress Android.bpsanitize: { hwaddress: true }

如果需要在整体构建中,去除某模块HWASAN的编译

Android.mkLOCAL_NOSANITIZE := hwaddress Android.bpsanitize: { hwaddress: false}

4. 解析

由于版本默认库或者bin是stripped过的,因此无法解析,如

==4415==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x003a861bb057 at pc 0x00775f3c664c bp 0x007fd0f434b0 sp 0x007fd0f42c90READ of size 8 at 0x003a861bb057 thread T0    #0 0x775f3c6648  (/system/lib64/libclang_rt.asan-aarch64-android.so+0x72648)    #1 0x775f3c6ff8  (/system/lib64/libclang_rt.asan-aarch64-android.so+0x72ff8)    #2 0x59861bf0a8  (/vendor/bin/qrtr-lookup+0x20a8)    #3 0x775f72488c  (/apex/com.android.runtime/lib64/bionic/libc.so+0x4988c) 0x003a861bb057 is located 0 bytes to the right of 7-byte region [0x003a861bb050,0x003a861bb057)allocated by thread T0 here:    #0 0x775f3f6088  (/system/lib64/libclang_rt.asan-aarch64-android.so+0xa2088)    #1 0x59861bf094  (/vendor/bin/qrtr-lookup+0x2094)    #2 0x775f72488c  (/apex/com.android.runtime/lib64/bionic/libc.so+0x4988c)    #3 0x59861bf044  (/vendor/bin/qrtr-lookup+0x2044)    #4 0x7760b9fbb4  (/vendor/bin/qrtr-lookup+0x4cbb4) SUMMARY: AddressSanitizer: heap-buffer-overflow (/system/lib64/libclang_rt.asan-aarch64-android.so+0x72648)Shadow bytes around the buggy address:  0x001750c375b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x001750c375c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x001750c375d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x001750c375e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x001750c375f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00=>0x001750c37600: fa fa 00 fa fa fa 00 fa fa fa[07]fa fa fa fa fa  0x001750c37610: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa  0x001750c37620: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa  0x001750c37630: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa  0x001750c37640: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa  0x001750c37650: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa faShadow byte legend (one shadow byte represents 8 application bytes):  Addressable:           00  Partially addressable: 01 02 03 04 05 06 07  Heap left redzone:       fa  Freed heap region:       fd  Stack left redzone:      f1  Stack mid redzone:       f2  Stack right redzone:     f3  Stack after return:      f5  Stack use after scope:   f8  Global redzone:          f9  Global init order:       f6  Poisoned by user:        f7  Container overflow:      fc  Array cookie:            ac  Intra object redzone:    bb  ASan internal:           fe  Left alloca redzone:     ca  Right alloca redzone:    cb  Shadow gap:              cc==4415==ABORTING

4.1 直接解析

  • push llvm-symbolizer到 system/bin下
    • 如 push到其他目录,需要保证该目录在PATH下或者设置环境变量export ASAN_SYMBOLIZER_PATH=/system/bin/llvm-symbolizer
    •  llvm-symbolizer路径:android\vendor\qcom\proprietary\llvm-arm-toolchain-ship\10.0\aarch64-linux-android\bin\llvm-symbolizer
  • push 对应模块带有symbols的库或者bin到对应目录,源文件位于android\out\target\product\shift\symbols

上述工作完成后,当ASAN / HWASan 检查到错误后,相关结果会自动解析到loGCat 或screen 上,包括具体的函数,行号等等

====================================================================6646==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x003c452d8057 at pc 0x00749d4d364c bp 0x007fd09ac530 sp 0x007fd09abd10READ of size 8 at 0x003c452d8057 thread T0    #0 0x749d4d3648 in printf_common(void*, char const*, std::__va_list) /out/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors_format.inc:547:9    #1 0x749d4d3ff8 in __interceptor_vprintf /out/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:1645:1    #2 0x749d4d3ff8 in printf /out/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:1703:1    #3 0x5b452dc1a8 in main vendor/qcom/proprietary/qmi-framework/qrtr/src/lookup.c:143:5    #4 0x749d3a888c in __libc_init (/apex/com.android.runtime/lib64/bionic/libc.so+0x4988c) 0x003c452d8057 is located 0 bytes to the right of 7-byte region [0x003c452d8050,0x003c452d8057)allocated by thread T0 here:    #0 0x749d503088 in malloc /out/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3    #1 0x5b452dc194 in main vendor/qcom/proprietary/qmi-framework/qrtr/src/lookup.c:142:21    #2 0x749d3a888c in __libc_init (/apex/com.android.runtime/lib64/bionic/libc.so+0x4988c)    #3 0x5b452dc044 in _start_main bionic/libc/arch-common/bionic/crtbegin.c:45:3    #4 0x749eb2dbb4  (/vendor/bin/qrtr-lookup+0x4cbb4) SUMMARY: AddressSanitizer: heap-buffer-overflow /out/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors_format.inc:547:9 in printf_common(void*, char const*, std::__va_list)Shadow bytes around the buggy address:  0x001788a5afb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x001788a5afc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x001788a5afd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x001788a5afe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x001788a5aff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00=>0x001788a5b000: fa fa 00 fa fa fa 00 fa fa fa[07]fa fa fa fa fa  0x001788a5b010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa  0x001788a5b020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa  0x001788a5b030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa  0x001788a5b040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa  0x001788a5b050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa faShadow byte legend (one shadow byte represents 8 application bytes):  Addressable:           00  Partially addressable: 01 02 03 04 05 06 07  Heap left redzone:       fa  Freed heap region:       fd  Stack left redzone:      f1  Stack mid redzone:       f2  Stack right redzone:     f3  Stack after return:      f5  Stack use after scope:   f8  Global redzone:          f9  Global init order:       f6  Poisoned by user:        f7  Container overflow:      fc  Array cookie:            ac  Intra object redzone:    bb  ASan internal:           fe  Left alloca redzone:     ca  Right alloca redzone:    cb  Shadow gap:              cc==6646==ABORTINGAborted

4.2 编译带symbols 的lib/bin(单独模块进行排错)

  • ASAN/HWASan,push 额外libc++_shared.so
    • 命令 adb push android\prebuilts\ndk\r21\sources\cxx-stl\llvm-libc++\libs\arm64-v8a\libc++_shared.so /system/lib64
  • HWASan 需要额外push  libclang_rt.hwasan-aarch64-android.so库
  • push llvm-symbolizer到system/bin下
  • 模块的编译脚本携带如下参数
Android.mkLOCAL_STRIP_MODULE :=falseAndroid.bpstrip :{keep_symbols: true,},

可得到如下信息,得到具体的函数

==10804==ERROR: HWAddressSanitizer: invalid-free on address 0x0038f7647040 at pc 0x0072ed942bb8tags: 1a/96 (ptr/mem)    #0 0x72ed942bb4 in __sanitizer_free /out/llvm-project/compiler-rt/lib/hwasan/hwasan_interceptors.cpp:108:3    #1 0x57f764b0b8 in main (/vendor/bin/qrtr-lookup+0x20b8)    #2 0x72ed831174 in __libc_init (/apex/com.android.runtime/lib64/bionic/libc.so+0x4e174)    #3 0x57f764b044 in _start_main (/vendor/bin/qrtr-lookup+0x2044)    #4 0x72eefd3bb4  (/vendor/bin/qrtr-lookup+0x4cbb4) [0x0038f7647040,0x0038f7647060) is a small unallocated heap chunk; size: 32 offset: 00x0038f7647040 is located 0 bytes inside of 7-byte region [0x0038f7647040,0x0038f7647047)freed by thread T0 here:    #0 0x72ed942bb4 in __sanitizer_free /out/llvm-project/compiler-rt/lib/hwasan/hwasan_interceptors.cpp:108:3    #1 0x57f764b0b0 in main (/vendor/bin/qrtr-lookup+0x20b0)    #2 0x72ed831174 in __libc_init (/apex/com.android.runtime/lib64/bionic/libc.so+0x4e174)    #3 0x57f764b044 in _start_main (/vendor/bin/qrtr-lookup+0x2044)    #4 0x72eefd3bb4  (/vendor/bin/qrtr-lookup+0x4cbb4) previously allocated here:    #0 0x72ed943084 in __sanitizer_malloc /out/llvm-project/compiler-rt/lib/hwasan/hwasan_interceptors.cpp:169:3    #1 0x72ed826bdc in malloc (/apex/com.android.runtime/lib64/bionic/libc.so+0x43bdc)    #2 0x57f764b094 in main (/vendor/bin/qrtr-lookup+0x2094)    #3 0x72ed831174 in __libc_init (/apex/com.android.runtime/lib64/bionic/libc.so+0x4e174)    #4 0x57f764b044 in _start_main (/vendor/bin/qrtr-lookup+0x2044)    #5 0x72eefd3bb4  (/vendor/bin/qrtr-lookup+0x4cbb4) hwasan_dev_note_heap_rb_distance: 1 1023Thread: T0 0x006900002000 stack: [0x007fd2fc0000,0x007fd37c0000) sz: 8388608 tls: [0x000000000000,0x000000000000)Memory tags around the buggy address (one tag corresponds to 16 bytes):  0x006d8f764680: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f764690: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f7646a0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f7646b0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f7646c0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f7646d0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f7646e0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f7646f0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00=>0x006d8f764700: 08  00  08  00 [96] 00  00  00  00  00  00  00  00  00  00  00  0x006d8f764710: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f764720: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f764730: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f764740: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f764750: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f764760: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f764770: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  0x006d8f764780: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00Tags for short granules around the buggy address (one tag corresponds to 16 bytes):  0x006d8f7646f0: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..=>0x006d8f764700: e2  ..  7a  .. [..] ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  0x006d8f764710: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html#short-granules for a description of short granule tagsSUMMARY: HWAddressSanitizer: invalid-free /out/llvm-project/compiler-rt/lib/hwasan/hwasan_interceptors.cpp:108:3 in __sanitizer_free

4.3 host 解析

将dump信息copy进入文件dumpinfo,按照如下格式(===开头)

===================================================================24786==ERROR: AddressSanitizer: SEGV on unknown address 0x180001a46bc1c34 (pc 0x00761175f308 bp 0x007fc5f519b0 sp 0x007fc5f51970 T0)==24786==The signal is caused by a READ memory access.    #0 0x761175f308  (/system/system_ext/lib64/libimsmedia_jni.so+0x3308)    #1 0x761175f1b8 in JNI_OnLoad (/system/system_ext/lib64/libimsmedia_jni.so+0x31b8)    #2 0x7681c104d8 in art::JavaVMExt::LoadNativeLibrary(_JNIEnv*, std::__1::basic_string, std::__1::allocator > const&, _jobject*, _jclass*, std::__1::basic_string, std::__1::allocator >*) (/apex/com.android.art/lib64/libart.so+0x5be4d8)    #3 0x7678bf2128 in JVM_NativeLoad (/apex/com.android.art/lib64/libopenjdkjvm.so+0x8128)    #4 0x6fba7a24  (/apex/com.android.art/javalib/arm64/boot.oat+0x80a24)

然后执行(asan_symbolize路径,android\external\compiler-rt\lib\asan\scripts)

asan_symbolize -s "$OUT/symbols"/ < ./external/compiler-rt/lib/asan/scripts/dumpinfo
#0 0x7332a21308 in _Z18load_ims_media_libPKc vendor/qcom/proprietary/commonsys/telephony-apps/ims/jni/media/ims_media_jni.cpp:477:56   #1 0x7332a211b8 in _Z18load_ims_media_libPKc vendor/qcom/proprietary/commonsys/telephony-apps/ims/jni/media/ims_media_jni.cpp:0:0   #2 0x73a24dc168 in _ZN3art9JavaVMExt17LoadNativeLibraryEP7_JNIEnvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEP8_jobjectP7_jclassPS9_ art/runtime/jni/java_vm_ext.cc:1080:19   #3 0x7399a1b16c in JVM_NativeLoad art/openjdkjvm/OpenjdkJvm.cc:333:24

5. FAQ

5.1 system 编译失败

由于当前为非动态分区,且system分区大小为1.5G,开启ASAN/HWASAN后,编译的system.img超过了1.5G,因此需要按照如下修改(后续改成动态分区则不需要修改了)

partionvi device/jxx/shift/BoardConfig.mkifneq ($(strip $(BOARD_DYNAMIC_PARTITION_ENABLE)),true)#BOARD_BUILD_SYSTEM_ROOT_IMAGE := trueBOARD_VENDORIMAGE_PARTITION_SIZE := 1043333120 #1073741824ifeq ($(strip $(WITH_GMS)),true)BOARD_SYSTEMIMAGE_PARTITION_SIZE := 3093299200 #3221225472elseBOARD_SYSTEMIMAGE_PARTITION_SIZE := 3093299200 #1610612736endifBOARD_PRODUCTIMAGE_PARTITION_SIZE := 838860800ifeq ($(ENABLE_AB), true)AB_OTA_PARTITIONS ?= systemendifelse

5.2 Not enough space to resize partition

烧录system时,提示无足够空间,因为当前ROM是4G,而system.img超过了1.5G,烧录system时,除了system.img,还剩余空间少于1.5G,因此失败,此时需要将system和vendor打包为super.img烧录

  • super打包命令
lpmake --metadata-size 65536 --super-name super --metadata-slots 3 --virtual-ab --device super:4294967296 \       --group Qti_dynamic_partitions_a:4290772992  --group qti_dynamic_partitions_b:4290772992 \       --partition system_a:readonly:$(get_build_var BOARD_SYSTEMIMAGE_PARTITION_SIZE):qti_dynamic_partitions_a --image system_a=$OUT/system.img \       --partition system_b:readonly:0:qti_dynamic_partitions_b \       --partition system_ext_a:readonly:0:qti_dynamic_partitions_a \       --partition system_ext_b:readonly:0:qti_dynamic_partitions_b \       --partition product_a:readonly:0:qti_dynamic_partitions_a \       --partition product_b:readonly:0:qti_dynamic_partitions_b \       --partition vendor_a:readonly:$(get_build_var BOARD_VENDORIMAGE_PARTITION_SIZE):qti_dynamic_partitions_a --image vendor_a=$OUT/vendor.img \       --partition vendor_b:readonly:0:qti_dynamic_partitions_b \       --sparse --output $OUT/super.img
  • super烧录命令
fastboot flash super super.img

5.3 userdata 烧录

由于文件系统的不同,烧录userdata会导致系统无法启动,因此在烧录特殊版本的ASAN时,不烧录userdata.img,待system、vendor烧录启动后,push $OUT/data/asan到板卡的data目录下即可

来源地址:https://blog.csdn.net/jingerppp/article/details/131322020

--结束END--

本文标题: ASan和HWAsan在Android中使用

本文链接: https://lsjlt.com/news/393175.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • ASan和HWAsan在Android中使用
    1. ASan和HWAsan比较 ASan HWASan 全称 Address Sanitizer Hardware-assisted AddressSanitizer 版本 可以在32位和64位的x86、x86-64上。 从...
    99+
    2023-09-04
    android asan hwasan
  • 在android中使用缓存和脱机存储
    目录1、在android中使用缓存和脱机存储2、Offline storage离线存储1、在android中使用缓存和脱机存储   缓存可以加速你的应用程序,即使在网络不可用时,用户...
    99+
    2024-04-02
  • 一文详解在Android中Service和AIDL的使用
    目录Service 和 AIDL 的使用1. Service1.1 Service 的基本生命周期1.1.1 startService1.1.2 bindService1.2 Ser...
    99+
    2023-05-18
    Android Service和AIDL的使用 Android Service使用 Android AIDL使用
  • EditText怎么在Android中使用
    本篇文章给大家分享的是有关EditText怎么在Android中使用,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Android是什么Android是一种基于Linux内核的自...
    99+
    2023-06-14
  • Fragment如何在Android中使用
    本篇文章给大家分享的是有关Fragment如何在Android中使用,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Fragment初探为了让界面可以在平板上更好地展示,Andr...
    99+
    2023-06-14
  • AppWidget怎么在Android中使用
    AppWidget怎么在Android中使用?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。一、在AndroidManifest.xml中声明一个AppWidge...
    99+
    2023-06-14
  • BroadcastReceiver怎么在Android中使用
    这篇文章给大家介绍 BroadcastReceiver怎么在Android中使用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Android是什么Android是一种基于Linux内核的自由及开放源代码的操作系统,主要...
    99+
    2023-06-14
  • ViewBinding怎么在Android中使用
    ViewBinding怎么在Android中使用?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。ViewBinding 有什么作用过于冗余findViewById...
    99+
    2023-06-15
  • RecyclerView怎么在Android中使用
    RecyclerView怎么在Android中使用?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。首先ListView与RecyclerView两者非常相似,两者提供view都是...
    99+
    2023-05-30
    recyclerview android
  • ijkplayer如何在android中使用
    这期内容当中小编将会给大家带来有关ijkplayer如何在android中使用,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。导入到你的项目中android studio打开你的项目,File->Im...
    99+
    2023-05-30
    android ijkplayer
  • 怎么在Android中使用menu
    这篇文章将为大家详细讲解有关怎么在Android中使用menu,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。①在res下的menu中创建file_menu.xml:<xml ...
    99+
    2023-05-30
    android menu
  • Notification怎么在Android中使用
    这期内容当中小编将会给大家带来有关Notification怎么在Android中使用,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。用法首先我们需要一个NotificationManager来对通知进行管理...
    99+
    2023-05-30
    android notification
  • SharedPreferences怎么在Android中使用
    这篇文章给大家介绍SharedPreferences怎么在Android中使用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。MainActivity:public class SharedPrefe...
    99+
    2023-05-30
    android sharedpreferences
  • Shape如何在Android中使用
    本篇文章给大家分享的是有关Shape如何在Android中使用,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。ShapeDrawable是一种很常见的Drawable,可以理解为...
    99+
    2023-05-31
    android shape roi
  • 如何在Android中使用Surfaceview
    如何在Android中使用Surfaceview?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。一.surfaceview与view的区别Android 提供了v...
    99+
    2023-05-30
    android surfaceview
  • webview如何在Android中使用
    这篇文章给大家介绍webview如何在Android中使用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Androi1. 打开网页时不调用系统浏览器, 而是在本WebView中显示:mWebView.setWebVie...
    99+
    2023-05-30
    android webview
  • StringBuffer怎么在Android中使用
    StringBuffer怎么在Android中使用?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1、StringBuffer对象的初始化StringBuffer对象的初始化不像...
    99+
    2023-05-30
    android stringbuffer
  • 怎么在Android中使用ExpandableRecyclerView
    怎么在Android中使用ExpandableRecyclerView?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。使用步骤:加入依赖compile ...
    99+
    2023-05-30
    android
  • CheckBox怎么在Android中使用
    CheckBox怎么在Android中使用?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。activity_main.xml<xml versio...
    99+
    2023-05-30
    android checkbox
  • RadioGroup如何在Android中使用
    本篇文章给大家分享的是有关RadioGroup如何在Android中使用,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。具体如下:activity_main.xml<xml...
    99+
    2023-05-30
    android radiogroup
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作