2572人阅读 评论(4) 收藏 举报 Android NTFS exFAT 自动挂载 源代码

目录(?)[+]

Android 不支持 NTFS 和 exFAT 格式的文件系统,但是 Linux 已经有相应的开源代码了,因此只需将其移植到 Android 上即可。

这里需要下载两份代码,分别是 ntfs-3g 和 exfat。下载地址ntfs-3gexfat。

由于 Android 并没有使用完整的 glibc 库,因此需要对源代码进行修改以使代码能被顺利地编译。


代码与编译好的文件都可以在 CSDN 资源里下载:

CyanogenMod10 ntfs 与 exfat 自动挂载支持


一、修改 ntfs-3g 代码

关于 ntfs-3g 代码的修改,可以参考 CSDN 上的这篇文章:ntfs-3g移植到android4.0.3方法总结。这里就不在重复叙述了。


二、修改 exfat 代码

exfat 也是使用了 fuse,但代码量很小。需要修改的地方不多:

1、fuse/main.c 文件

大约位于 264 行的fuse_exfat_statfs 函数,将参数中的 statvfs 改为 statfs,并将其代码中的sfs->f_namemax 改为sfs->f_namelen

[cpp] view plain copy
  1. sfs->f_favail=sfs->f_bfree>>ef.sb->spc_bits;
  2. sfs->f_ffree=sfs->f_bavail;
改为

[cpp] view plain copy
  1. sfs->f_ffree=sfs->f_bfree>>ef.sb->spc_bits;

2、libexfat/io.c

大约位于 255 行的exfat_seek 函数,将里面的 lseek 函数改为 lseek64;

大约位于 283 行的exfat_pread 函数,将里面的 pread 函数改为 pread64;

大约位于 295 行的exfat_pwrite 函数,将里面的 pwrite 函数改为 pwrite64。

3、将所有代码文件中的 off_t 类型全部换为 off64_t 类型

Android 的编译器编译出来的 off_t 类型是4字节的,只有改为 off64_t 才是8字节的。不改的话无法挂载超过 4G 的 SD 卡或 U 盘。


三、提取文件,编写 Android.mk 文件

这里我将所有的项目都放在了和 vold 同级的 system 目录下

1、libfuse

由于 ntfs-3g 和 exfat 都使用了 fuse,因此他们可以共享这个库。

在 system 目录新建 libfuse 文件夹,并建立子文件夹 src 和 include。将 ntfs-3g 中 libfuse-lite 中的所有文件复制到 libfuse/src 目录中,将 ntfs-3g 中 include/fuse-lite 中的所有文件复制到 libfuse/include 目录中,将 ntfs-3g 中的 config.h 复制到 libfuse 目录。

修改 libfuse/src/helper.c,在最后添加如下代码(exfat 需要):

[cpp] view plain copy
  1. intfuse_daemonize(intforeground)
  2. {
  3. intres;
  4. if(!foreground){
  5. res=daemon(0,0);
  6. if(res==-1){
  7. perror("fuse:failedtodaemonizeprogram\n");
  8. return-1;
  9. }
  10. }
  11. return0;
  12. }

在 libfuse 目录编写 Android.mk:

[plain] view plain copy
  1. LOCAL_PATH:=$(callmy-dir)
  2. include$(CLEAR_VARS)
  3. LOCAL_SRC_FILES:=\
  4. src/fuse.c\
  5. src/fusermount.c\
  6. src/fuse_kern_chan.c\
  7. src/fuse_loop.c\
  8. src/fuse_lowlevel.c\
  9. src/fuse_opt.c\
  10. src/fuse_session.c\
  11. src/fuse_signals.c\
  12. src/helper.c\
  13. src/mount.c\
  14. src/mount_util.c
  15. LOCAL_C_INCLUDES:=$(LOCAL_PATH)/include
  16. LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DHAVE_CONFIG_H
  17. LOCAL_MODULE:=libfuse
  18. LOCAL_MODULE_TAGS:=eng
  19. LOCAL_SYSTEM_SHARED_LIBRARIES:=libclibcutils
  20. include$(BUILD_STATIC_LIBRARY)

2、ntfs-3g

则里只提取挂载 NTFS 分区的文件。

在 system 目录新建 ntfs-3g 文件夹,并建立子文件夹 include、libntfs-3g 和 src。将 ntfs-3g 中 include/ntfs-3g 中的所有文件复制到 ntfs-3g/include 目录中,将 ntfs-3g 中 libntfs-3g 中的所有文件复制到 ntfs-3g/libntfs-3g 目录中,将 ntfs-3g 中 src 目录中的 ntfs-3g.c ntfs-3g_common.c ntfs-3g_common.h 复制到 ntfs-3g/src 目录中,将 ntfs-3g 中的 config.h 复制到 ntfs-3g 目录。

在 ntfs-3g 目录中编写 Android.mk:

[plain] view plain copy
  1. LOCAL_PATH:=$(callmy-dir)
  2. include$(CLEAR_VARS)
  3. LOCAL_SRC_FILES:=\
  4. libntfs-3g/acls.clibntfs-3g/attrib.clibntfs-3g/attrlist.c\
  5. libntfs-3g/bitmap.clibntfs-3g/bootsect.clibntfs-3g/cache.c\
  6. libntfs-3g/collate.clibntfs-3g/compat.clibntfs-3g/compress.c\
  7. libntfs-3g/debug.clibntfs-3g/device.clibntfs-3g/dir.c\
  8. libntfs-3g/efs.clibntfs-3g/index.clibntfs-3g/inode.c\
  9. libntfs-3g/lcnalloc.clibntfs-3g/logfile.clibntfs-3g/logging.c\
  10. libntfs-3g/mft.clibntfs-3g/misc.clibntfs-3g/mst.c\
  11. libntfs-3g/object_id.clibntfs-3g/realpath.clibntfs-3g/reparse.c\
  12. libntfs-3g/runlist.clibntfs-3g/security.clibntfs-3g/unistr.c\
  13. libntfs-3g/unix_io.clibntfs-3g/volume.c
  14. LOCAL_C_INCLUDES:=$(LOCAL_PATH)/includesystem/libfuse/include
  15. LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DHAVE_CONFIG_H
  16. LOCAL_MODULE:=libntfs-3g
  17. LOCAL_MODULE_TAGS:=eng
  18. LOCAL_SYSTEM_SHARED_LIBRARIES:=libclibcutils
  19. include$(BUILD_STATIC_LIBRARY)
  20. include$(CLEAR_VARS)
  21. LOCAL_SRC_FILES:=\
  22. src/ntfs-3g.csrc/ntfs-3g_common.c
  23. LOCAL_C_INCLUDES:=$(LOCAL_PATH)/include$(LOCAL_PATH)/srcsystem/libfuse/include
  24. LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DHAVE_CONFIG_H
  25. LOCAL_MODULE:=ntfs-3g
  26. LOCAL_MODULE_TAGS:=eng
  27. LOCAL_SYSTEM_SHARED_LIBRARIES:=libc
  28. LOCAL_STATIC_LIBRARIES:=libfuselibntfs-3g
  29. include$(BUILD_EXECUTABLE)

3、ntfsfix

这个是用来在挂载 NTFS 分区前检查错误的。

在 system 目录下建立 ntfsfix 目录,并建立子目录 src。将 ntfs-3g 中 ntfsprogs 中的 ntfsfix.c sd.c sd.h utils.c utils.h 复制到 ntfsfix/src 目录,将 ntfs-3g 中的 config.h 复制到 ntfsfix 目录。

在 ntfsfix 目录下建立 Android.mk:

[plain] view plain copy
  1. LOCAL_PATH:=$(callmy-dir)
  2. include$(CLEAR_VARS)
  3. LOCAL_SRC_FILES:=\
  4. src/ntfsfix.c\
  5. src/utils.c\
  6. src/sd.c
  7. LOCAL_C_INCLUDES:=$(LOCAL_PATH)/srcsystem/ntfs-3g/include
  8. LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DHAVE_CONFIG_H
  9. LOCAL_MODULE:=ntfsfix
  10. LOCAL_MODULE_TAGS:=eng
  11. LOCAL_SYSTEM_SHARED_LIBRARIES:=libc
  12. LOCAL_STATIC_LIBRARIES:=libntfs-3glibfuse
  13. include$(BUILD_EXECUTABLE)

4、mkntfs

这个是用来格式化分区为 NTFS 格式的。

在 system 目录下建立 mkntfs 目录,并建立子目录 src。将 ntfs-3g 中 ntfsprogs 中的 attrdef.c attrdef.h boot.c boot.h mkntfs.c sd.c sd.h utils.c utils.h 复制到 mkntfs/src 目录,将 ntfs-3g 中的 config.h 复制到 mkntfs 目录。

在 mkntfs 目录下建立 Android.mk:

[plain] view plain copy
  1. LOCAL_PATH:=$(callmy-dir)
  2. include$(CLEAR_VARS)
  3. LOCAL_SRC_FILES:=\
  4. src/attrdef.c\
  5. src/boot.c\
  6. src/utils.c\
  7. src/mkntfs.c\
  8. src/sd.c
  9. LOCAL_C_INCLUDES:=$(LOCAL_PATH)/srcsystem/ntfs-3g/include
  10. LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DHAVE_CONFIG_H
  11. LOCAL_MODULE:=mkntfs
  12. LOCAL_MODULE_TAGS:=eng
  13. LOCAL_SYSTEM_SHARED_LIBRARIES:=libc
  14. LOCAL_STATIC_LIBRARIES:=libntfs-3glibfuse
  15. include$(BUILD_EXECUTABLE)

5、exfat

这里只提取挂载 exFAT 分区所需的文件。

在 system 目录下建立 exfat 目录。将 exfat 源代码中的 fuse 和 libexfat 文件夹复制到 exfat 目录中。

建立 Android.mk:

[plain] view plain copy
  1. LOCAL_PATH:=$(callmy-dir)
  2. include$(CLEAR_VARS)
  3. LOCAL_SRC_FILES:=\
  4. libexfat/cluster.clibexfat/io.clibexfat/log.c\
  5. libexfat/lookup.clibexfat/mount.clibexfat/node.c\
  6. libexfat/time.clibexfat/utf.clibexfat/utils.c
  7. LOCAL_C_INCLUDES:=$(LOCAL_PATH)/libexfatsystem/libfuse/include
  8. LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-UUSE_UBLIO
  9. LOCAL_MODULE:=libexfat
  10. LOCAL_MODULE_TAGS:=eng
  11. LOCAL_SYSTEM_SHARED_LIBRARIES:=libclibcutils
  12. include$(BUILD_STATIC_LIBRARY)
  13. include$(CLEAR_VARS)
  14. LOCAL_SRC_FILES:=\
  15. fuse/main.c
  16. LOCAL_C_INCLUDES:=$(LOCAL_PATH)/libexfatsystem/libfuse/include
  17. LOCAL_CFLAGS:=-O2-g-W-Wall-D_LARGEFILE_SOURCE-D_FILE_OFFSET_BITS=64-DUSE_UBLIO
  18. LOCAL_MODULE:=exfat
  19. LOCAL_MODULE_TAGS:=eng
  20. LOCAL_SYSTEM_SHARED_LIBRARIES:=libc
  21. LOCAL_STATIC_LIBRARIES:=libfuselibexfat
  22. include$(BUILD_EXECUTABLE)

6、exfatfsck

这个是用来在挂载 exFAT 分区前检查错误的。

在 system 目录建立 exfatfsck 目录,并将 exfat 源代码中 fsck/main.c 复制到 exfatfsck 目录中。

建立 Android.mk(这里只列出关键的两行):

[plain] view plain copy
  1. LOCAL_SRC_FILES:=\
  2. main.c
  3. LOCAL_C_INCLUDES:=$(LOCAL_PATH)/srcsystem/exfat/libexfat

7、mkexfatfs

这个是用来格式化分区为 exFAT 格式的。

在 system 目录下建立 mkexfatfs 目录,并建立子目录 src。将 exfat 源代码中 mkfs 目录下的所有文件复制到 mkexfatfs/src 目录中。

建立 Android.mk(关键部分):

[plain] view plain copy
  1. LOCAL_SRC_FILES:=\
  2. src/cbm.c\
  3. src/fat.c\
  4. src/main.c\
  5. src/mkexfat.c\
  6. src/rootdir.c\
  7. src/uct.c\
  8. src/uctc.c\
  9. src/vbr.c
  10. LOCAL_C_INCLUDES:=$(LOCAL_PATH)/srcsystem/exfat/libexfat


四、修改 vold 代码

CyanogenMod 的 vold 代码包含了 Ntfs.cpp 和 Ntfs.h,但是需要修改

1、修改 Ntfs.cpp

添加全局变量:

[cpp] view plain copy
  1. staticcharMOUNT_NTFS_PATH[]="/system/bin/ntfs-3g";
  2. staticcharMKNTFS_PATH[]="/system/bin/mkntfs";
  3. staticcharNTFSFIX_PATH[]="/system/bin/ntfsfix";

check 函数:

[cpp] view plain copy
  1. intNtfs::check(constchar*fsPath){
  2. boolrw=true;
  3. if(access(NTFSFIX_PATH,X_OK)){
  4. SLOGW("Skippingfschecks\n");
  5. return0;
  6. }
  7. intrc=-1;
  8. do{
  9. constchar*args[3];
  10. args[0]=NTFSFIX_PATH;
  11. args[1]=fsPath;
  12. args[2]=NULL;
  13. rc=logwrap(3,args,1);
  14. switch(rc){
  15. case0:
  16. SLOGI("NTFSFilesystemcheckcompletedOK.\n");
  17. return0;
  18. case1:
  19. SLOGI("NTFSFilesystemcheckfailed.\n");
  20. return0;
  21. default:
  22. SLOGE("NTFSFilesystemcheckfailed(unknownexitcode%d).\n",rc);
  23. errno=EIO;
  24. return-1;
  25. }
  26. }while(0);
  27. return0;
  28. }

doMount 函数:

[cpp] view plain copy
  1. intNtfs::doMount(constchar*fsPath,constchar*mountPoint,
  2. boolro,boolremount,boolexecutable,
  3. intownerUid,intownerGid,intpermMask,boolcreateLost){
  4. intrc;
  5. unsignedlongflags;
  6. charmountData[255];
  7. charoptions[255]={};
  8. constchar*args[6];
  9. flags=MS_NODEV|MS_NOSUID|MS_DIRSYNC;
  10. flags|=(executable?0:MS_NOEXEC);
  11. flags|=(ro?MS_RDONLY:0);
  12. flags|=(remount?MS_REMOUNT:0);
  13. //Testing/security,mountrouptonow
  14. flags|=MS_RDONLY;
  15. /*
  16. *Note:Thisisatemporaryhack.Ifthesamplingprofilerisenabled,
  17. *wemaketheSDcardworld-writablesoanyprocesscanwritesnapshots.
  18. *
  19. *TODO:Removethiscodeoncewehaveadropboxinsystem_server.
  20. */
  21. charvalue[PROPERTY_VALUE_MAX];
  22. property_get("persist.sampling_profiler",value,"");
  23. if(value[0]=='1'){
  24. SLOGW("TheSDcardisworld-writablebecausethe"
  25. "'persist.sampling_profiler'systempropertyissetto'1'.");
  26. permMask=0;
  27. }
  28. sprintf(mountData,
  29. "uid=%d,gid=%d,fmask=%o,dmask=%o",
  30. ownerUid,ownerGid,permMask,permMask);
  31. if(!remount){
  32. SLOGI("Tryingtousentfs-3gprogramtomount%s",fsPath);
  33. if(ro)
  34. snprintf(options,sizeof(options),"ro,%s",mountData);
  35. else
  36. snprintf(options,sizeof(options),"%s",mountData);
  37. args[0]=MOUNT_NTFS_PATH;
  38. args[1]="-o";
  39. args[2]=options;
  40. args[3]=fsPath;
  41. args[4]=mountPoint;
  42. args[5]=NULL;
  43. rc=logwrap(6,args,1);
  44. if(rc==0){
  45. SLOGI("ntfs-3gexecutedsuccessfully.");
  46. }else{
  47. SLOGE("Failedtoexecutentfs-3g.");
  48. }
  49. }else{
  50. rc=mount(fsPath,mountPoint,"fuseblk",flags,mountData);
  51. }
  52. if(rc&&errno==EROFS){
  53. SLOGE("%sappearstobeareadonlyfilesystem-retryingmountRO",fsPath);
  54. flags|=MS_RDONLY;
  55. if(!remount){
  56. SLOGI("Tryingtousentfs-3gprogramtomount%sasread-only",fsPath);
  57. snprintf(options,sizeof(options),"ro,%s",mountData);
  58. args[0]=MOUNT_NTFS_PATH;
  59. args[1]="-o";
  60. args[2]=options;
  61. args[3]=fsPath;
  62. args[4]=mountPoint;
  63. args[5]=NULL;
  64. rc=logwrap(6,args,1);
  65. if(rc==0){
  66. SLOGI("ntfs-3gexecutedsuccessfullyforread-only.");
  67. }else{
  68. SLOGE("Failedtoexecutentfs-3gforread-only.");
  69. }
  70. }else{
  71. rc=mount(fsPath,mountPoint,"fuseblk",flags,mountData);
  72. }
  73. }
  74. returnrc;
  75. }

format 函数:

[cpp] view plain copy
  1. intNtfs::format(constchar*fsPath,unsignedintnumSectors){
  2. constchar*args[5];
  3. charstrNumOfSectors[16]={};
  4. intrc;
  5. args[0]=MKNTFS_PATH;
  6. args[1]="-f";
  7. args[2]=fsPath;
  8. if(numSectors){
  9. snprintf(strNumOfSectors,sizeof(strNumOfSectors),"%u",numSectors);
  10. args[3]=strNumOfSectors;
  11. args[4]=NULL;
  12. rc=logwrap(5,args,1);
  13. }else{
  14. args[3]=NULL;
  15. rc=logwrap(4,args,1);
  16. }
  17. if(rc==0){
  18. SLOGI("FilesystemformattedOK");
  19. return0;
  20. }else{
  21. SLOGE("Formatfailed(unknownexitcode%d)",rc);
  22. errno=EIO;
  23. return-1;
  24. }
  25. return0;
  26. }

2、添加 ExFat.h 和 ExFat.cpp

这里请使用 Ntfs.h 和 Ntfs.cpp 作为模板。

关键代码:

[cpp] view plain copy
  1. staticcharMOUNT_EXFAT_PATH[]="/system/bin/exfat";
  2. staticcharMKFS_EXFAT_PATH[]="/system/bin/mkexfatfs";
  3. staticcharFSCK_EXFAT_PATH[]="/system/bin/exfatfsck";
  4. intExFat::check(constchar*fsPath){
  5. boolrw=true;
  6. if(access(FSCK_EXFAT_PATH,X_OK)){
  7. SLOGW("Skippingfschecks\n");
  8. return0;
  9. }
  10. intrc=-1;
  11. do{
  12. constchar*args[3];
  13. args[0]=FSCK_EXFAT_PATH;
  14. args[1]=fsPath;
  15. args[2]=NULL;
  16. rc=logwrap(3,args,1);
  17. switch(rc){
  18. case0:
  19. SLOGI("exFATFilesystemcheckcompletedOK.\n");
  20. return0;
  21. case1:
  22. SLOGI("exFATFilesystemcheckfailed.\n");
  23. return0;
  24. default:
  25. SLOGE("exFATFilesystemcheckfailed(unknownexitcode%d).\n",rc);
  26. errno=EIO;
  27. return-1;
  28. }
  29. }while(0);
  30. return0;
  31. }
  32. intExFat::doMount(constchar*fsPath,constchar*mountPoint,
  33. boolro,boolremount,boolexecutable,
  34. intownerUid,intownerGid,intpermMask,boolcreateLost){
  35. intrc;
  36. unsignedlongflags;
  37. charmountData[255];
  38. constchar*args[4];
  39. flags=MS_NODEV|MS_NOSUID|MS_DIRSYNC;
  40. flags|=(executable?0:MS_NOEXEC);
  41. flags|=(ro?MS_RDONLY:0);
  42. flags|=(remount?MS_REMOUNT:0);
  43. //Testing/security,mountrouptonow
  44. flags|=MS_RDONLY;
  45. sprintf(mountData,
  46. "uid=%d,gid=%d,fmask=%o,dmask=%o",
  47. ownerUid,ownerGid,permMask,permMask);
  48. if(!remount){
  49. SLOGI("Tryingtouseexfatprogramtomount%s",fsPath);
  50. args[0]=MOUNT_EXFAT_PATH;
  51. args[1]=fsPath;
  52. args[2]=mountPoint;
  53. args[3]=NULL;
  54. rc=logwrap(4,args,1);
  55. if(rc==0){
  56. SLOGI("exfatexecutedsuccessfully.");
  57. }else{
  58. SLOGE("Failedtoexecuteexfat.");
  59. }
  60. }else{
  61. rc=mount(fsPath,mountPoint,"fuseblk",flags,mountData);
  62. }
  63. returnrc;
  64. }
  65. intExFat::format(constchar*fsPath,unsignedintnumSectors){
  66. constchar*args[3];
  67. charstrNumOfSectors[16]={};
  68. intrc;
  69. args[0]=MKFS_EXFAT_PATH;
  70. args[1]=fsPath;
  71. args[2]=NULL;
  72. rc=logwrap(3,args,1);
  73. if(rc==0){
  74. SLOGI("FilesystemformattedOK");
  75. return0;
  76. }else{
  77. SLOGE("Formatfailed(unknownexitcode%d)",rc);
  78. errno=EIO;
  79. return-1;
  80. }
  81. return0;
  82. }

3、修改 Volume.cpp

添加#include "Ntfs.h"

找到Volume::mountVol() 函数

找到else if (strcmp(fstype, "ntfs") == 0) 部分,在后面添加以下代码:

[cpp] view plain copy
  1. if(Ntfs::check(devicePath)){
  2. errno=EIO;
  3. /*Badness-abortthemount*/
  4. SLOGE("%sfailedFSchecks(%s)",devicePath,strerror(errno));
  5. setState(Volume::State_Idle);
  6. free(fstype);
  7. return-1;
  8. }

找到和if (fstype != NULL) 对应的 else 块,在后面添加以下代码:

[cpp] view plain copy
  1. //CheckifthefilesystemisexFAT
  2. FILE*volf=fopen(devicePath,"rb");
  3. intbytesRead=0;
  4. if(volf){
  5. charfschar[5];
  6. //ReadthesignatureinthePBR
  7. fseek(volf,3,SEEK_SET);
  8. bytesRead=fread(fschar,1,5,volf);
  9. fclose(volf);
  10. if(bytesRead==5&&strcmp(fschar,"EXFAT")==0){
  11. if(ExFat::check(devicePath)){
  12. errno=EIO;
  13. /*Badness-abortthemount*/
  14. SLOGE("%sfailedFSchecks(%s)",devicePath,strerror(errno));
  15. setState(Volume::State_Idle);
  16. free(fstype);
  17. return-1;
  18. }
  19. if(ExFat::doMount(devicePath,"/mnt/secure/staging",false,false,false,
  20. AID_SYSTEM,gid,0702,true)){
  21. SLOGE("%sfailedtomountviaexFAT(%s)\n",devicePath,strerror(errno));
  22. continue;
  23. }else{
  24. gotomountSuccess;
  25. }
  26. }
  27. }

然后转到 if (fstype != NULL) 的 else 的末尾,在语句块之后,SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint()); 之前添加mountSuccess: 跳转标签。

4、修改 vold 的 Android.mk

天际common_src_files += ExFat.c


五、修改 build/target/product/base.mk

添加

[plain] view plain copy
  1. PRODUCT_PACKAGES+=\
  2. libfuse\
  3. ntfs-3g\
  4. exfat\
  5. mkntfs\
  6. ntfsfix\
  7. mkexfatfs\
  8. exfatfsck



六、编译

如果不出意外的话,编译之后就可以直接使用了。

更多相关文章

  1. Android Studio 学习笔记(一)环境搭建、文件目录等相关说明
  2. Android中切换屏幕方向时Activity生命周期函数执行情况分析
  3. 如何在自己的程序中添加appWidget(附简单代码)
  4. Android两行代码真正杀死你的App
  5. Android代码混淆之混淆规则
  6. android:manageSpaceActivity让应用手动管理应用的数据目录
  7. Android Handler 异步消息处理机制 《第一行代码》

随机推荐

  1. Android软键盘显示模式及打开和关闭方式(
  2. 简解selector的几个属性
  3. Android布局属性介绍
  4. Android在layout xml中使用include
  5. Android(安卓)文件的上传
  6. Android 编译系统分析之返璞归真(一)
  7. Android极致优化
  8. Android的多语言文件转IOS多语言文件格式
  9. 安卓系统框架介绍
  10. Android与JNI(一)