1. 静态扫描流程

1.1 版本发布流程

大致分为5个阶段,静态代码扫描的工作在第3步进行,如图:

版本发布流程图

1.2 典型案例分析

[空指针]空指针引用

[内存泄露]Stream资源关闭

[性能]使用indexOf(字符)

[兼容]系统API兼容性隐患

[越界]数组下标越界隐患

[异常] 使用除法或求余没有判断分母长度隐患

[SQL]注入风险

[应用安全] AndroidMannifest.xml文件中allowBackup设置为true时会导致数据泄露

更多的错误检查示例请查看各检查工具的检查规则说明文档。

1.2.1 [空指针]空指针引用

错误位置:4

public class StringUtil {

public static final String queryParams(String param) {

String ret = "";

if (param != null || param.length() > 2) {

ret = param.substring(1, param.length() - 1);

}

return ret;

}

存在空指针引用,会导致空指针异常。解决方案:

public class StringUtil {

public static final String queryParams(String param) {

String ret = "";

if (param != null && param.length() > 2) {

ret = param.substring(1, param.length() - 1);

}

return ret;

}

1.2.2 [内存泄露]Stream资源关闭

错误位置:17

private static void write2logfile(String msg) {

try {

File sdCardDir = android.os.Environment

.getExternalStorageDirectory();

File logfile = new File(sdCardDir.getAbsolutePath()

+ File.separator + logfileName);

if (!logfile.exists()) {

logfile.createNewFile();

}

msg += "\n";

FileOutputStream outputStream = new FileOutputStream(logfile, true);

outputStream.write(msg.getBytes());

outputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

资源对象在被关闭或者Return之前可能出现异常,导致无法正常关闭或Return。比如连续关闭多个资源对象时没有进行异常捕获,或者资源对象在Return之前进行了未捕获异常的操作。解决方案:

private static void write2logfile(String msg) {

try {

File sdCardDir = android.os.Environment

.getExternalStorageDirectory();

File logfile = new File(sdCardDir.getAbsolutePath()

+ File.separator + logfileName);

if (!logfile.exists()) {

logfile.createNewFile();

}

msg += "\n";

FileOutputStream outputStream = new FileOutputStream(logfile, true);

outputStream.write(msg.getBytes());

} catch (IOException e) {

e.printStackTrace();

} finally{

if(null != outputStream){

outputStream.close();

}

}

}

1.2.3 [性能]使用indexOf(字符)

错误位置:340

338 int index = result.indexOf(Keyword);

339 line = result.substring(index + Keyword.length());

340 index = line.indexOf(" ");

341 kernelVersion = line.substring(0, index);

342 }

343 } catch (IndexOutOfBoundsException e) {

当你检测单个字符的位置时使用String.indexOf(字符),它执行的很快。

解决方案:不要使用indexOf(字符串)。

340 index = line.indexOf(' ');

1.2.4 [兼容]系统API兼容性隐患

public static String getSupportMap(Context context, String seInfo) {

StringBuffer support = new StringBuffer("000");

if (!"000".equals(seInfo)) {

support.setCharAt(2, '1');

}

if (VERSION.SDK_INT < 10) {

return support.toString();

}

NfcManager manager = (NfcManager) context

.getSystemService(Context.NFC_SERVICE);

NfcAdapter adapter = manager.getDefaultAdapter();

if (null == adapter) {

return support.toString();

} else {

if (adapter.isEnabled()) {

support.setCharAt(0, '1');

} else {

support.setCharAt(0, '2');

}

if (VERSION.SDK_INT >= 19) {

PackageManager pm = context.getPackageManager();

boolean hasNfcHce = pm

.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);

if (hasNfcHce) {

support.setCharAt(1, '1');

}

}

}

return support.toString();

}

getDefaultAdapter方法不支持:10(android2.3.3) 以下的版本。

解决方案:加入对版本的系统版本的判别

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) {

// 包含新API的代码块

else

{

// 包含旧的API的代码块

}

1.2.5 [越界]数组下标越界隐患

private void doSelectItem(int pos) {

mButtonViews[mSelectedButtonIndex].line.setVisibility(View.GONE);

mButtonViews[mSelectedButtonIndex].buttonText.setTextColor(Color.BLACK);

mButtonViews[mSelectedButtonIndex].contentView.setVisibility(View.GONE);

mButtonViews[pos].line.setVisibility(View.VISIBLE);

mButtonViews[pos].buttonText

.setTextColor(KDimens.K_COLOR_PROM_INDICATOR);

mButtonViews[pos].contentView.setVisibility(View.VISIBLE);

mSelectedButtonIndex = pos;

}

采用下标的方式获取数组元素时,如果下标越界,将产生java.lang.ArrayIndexOutOfBoundsException的异常,导致app出现Crash。

解决方案:在使用下标的方式获取数组元素时,需判断下标的有效性。

1.2.6 [异常] 使用除法或求余没有判断分母长度隐患

public static Drawable zoomDrawable(Context context, Drawable in, int scaledW, int scaledH) {

Drawable zoomed = null;

if (in instanceof BitmapDrawable) {

Bitmap bm = ((BitmapDrawable) in).getBitmap();

if (scaledH != -1 && scaledW == -1) {

scaledW = (int) ((float) (bm.getWidth() / bm.getHeight()) * scaledH);

} else if (scaledH == -1 && scaledW != -1) {

scaledH = (int) ((float) (bm.getHeight() / bm.getWidth()) * scaledW);

}

Bitmap sbm = Bitmap.createScaledBitmap(bm, scaledW, scaledW, true);

zoomed = new BitmapDrawable(context.getResources(), sbm);

}

return zoomed;

}

使用除法或者求余运算时,如果分母是通过调用函数返回的int,未对返回值进行判断,当返回值为0时,会出现java.lang.ArithmeticException: / by zero异常。

解决方案:调用函数前,对函数的返回值的长度进行判断。

1.2.6 [SQL]注入风险

描述:对Content Provider进行增删改查操作时,程序没有对用户的输入进行过滤,未采用参数化查询的方式,可能导致sql注入攻击。

代码示例:

private SQLiteDatabase db;

db.rawQuery("select * from person", null);//触发规则

推荐写法:

服务端充分校验参数

使用参数化查询,比如SQLiteStatement

避免使用rawQuery()方法

对用户输入进行过滤

SQLiteStatement sqLiteStatement = db.compileStatement("insert into msgTable(uid, msg) values(?, ?)");

sqLiteStatement.bindLong(1, 12);

sqLiteStatement.bindString(3, "text");

long newRowId = sqLiteStatement.executeInsert();

1.2.7 [应用安全] AndroidMannifest.xml文件中allowBackup设置为true时会导致数据泄露

描述:建议将AndroidMannifest.xml文件android:allowBackup属性设置为false。当allowBackup标志值为true时,攻击者可通过adb backup和adb restore来备份和恢复应用程序数据。

推荐写法:

描述:建议将AndroidMannifest.xml文件android:allowBackup属性设置为false。当allowBackup标志值为true时,攻击者可通过adb backup和adb restore来备份和恢复应用程序数据。

推荐写法:

minSdkVersion不低于9。

android:allowBackup属性显示设置为false。

1.3 Android 客户端扫描流程

分为3个阶段:

Android客户端扫描流程图

1.3.1 基础内容扫描

使用 Android Lint 对项目进行扫描,该工具已将扫描到的问题进行了分组,同时定义了问题的严重级别: error 和 warning。在 Android Studio 的 Inspection Results 视图窗中,点击问题标题即可在右边的详情视图中查看该问题的具体解释等内容,针对部分内容还有直接进行自动修复的按钮,如图:

Android Lint

关注点

由于检查的内容繁多,我们重点关注以下几个问题组的相关内容:

以 Android 开头的组,例如

Android > Lint > Correctness (可能影响程序正确性)

Android > Lint > Performance (可能影响程序性能)

Android > Lint > Security (可能影响程序安全性)

等等

Class structure 组:指出类的设计上可能存在的问题

Code style issues 组:有助于提供代码书写规范

Probable bugs 组:有助于发现隐藏的问题

检查通过标准

上述的列出的问题组别不出现或者出现但只包含warning类型的问题

1.3.2 可能引起Crash的问题扫描

使用360火线和Godeyes对项目进行扫描,下面将分别说明二者扫描时的关注点和检查通过标准:

360火线

360火线共有61个检查项,按级别分为Block、风险、建议和优化,检查报告以html文件输出,

在按规则分类查看的Tab中,可以查看具体问题位置及示例代码。如图

360 fireline

360 fireline

关注点

重点关注Block、风险两类标记的问题

检查通过标准

扫描结果中不出现Block、风险两类问题

Godeyes

Godeyes共检查23个错误,扫描结果以html文档的方式输出,文档中包含了检查问题的描述、示例以及推荐方案,方便理解。值得注意的是在扫描结果的显示上,报告只会给出问题所在的行号。如图

godeyes

关注点

所有列表检查出的问题。

检查通过标准

各扫描项扫描结果为0

1.3.3 空指针和资源泄露扫描

使用Infer工具对可能的空指针和可能的资源泄露进行扫描,Infer工具会在项目的根文件夹下生成infer-out的文件夹,重点关注bugs.txt这个文件,文件中会详细指出可能存在的问题的代码片段及相应的解释,示例如下:

Found 70 issues

219: error: RESOURCE_LEAK

resource of type `java.io.DataInputStream` acquired to `dis` by call to `new()` at line 159 is not released after line 219

**Note**: potential exception at line 164

217. dis.close();

218. is.close();

219. > } catch (IOException e) {

220. e.printStackTrace();

221. dr = null;

error: NULL_DEREFERENCE

object returned by `getItemByName("instalment")` could be null and is dereferenced at line 402

400. } else {

401. ((UPDropDownWidget) getItemByName(Rules.TYPE_INSTALMENT))

402. > .setmCanShow(true);

403. ((UPDropDownWidget) getItemByName(Rules.TYPE_INSTALMENT))

404. .onCheckBoxStatusChanged(true);

关注点

所有列表检查出的问题。

检查通过标准

对检查的问题尽量修复或者编写保护语句避免抛出异常。

2. 工具使用

以下内容均以 Android Studio 为默认的开发环境

2.1 Android Lint

该工具已经默认集成 Android Studio 中

使用方法:

Android Stuido -> 菜单栏 -> Analyze -> Inspect Code -> 根据需要选择相应的扫描范围 -> OK -> 启动扫描

如图:

Android Lint

Android Lint

Android Lint

参考资料

2.2 360 火线

使用方法

详情参考 官方使用方法

火线插件目前可以在Android Studio中进行在线搜索安装。

jar包版本使用

java -jar D:\test\fireline.jar -s=D:\test\TestCase -r=E:\RedlineReport

// 参数解释:

//【必填项】-s或scanSrcDir为被扫描的项目工程路径

//【必填项】-r或reportSaveDir为火线报告输出路径

360 fireline

Android stuido版本

Android Studio -> 菜单栏 -> File -> Settings... -> Plugins

搜索框 -> 搜索fireline -> install -> 重启

使用 -> Project视图 -> 鼠标右键 -> fireline -> run 生成报告

360 fireline

360 fireline

参考资料

2.3 Godeyes

使用方法

下载 Android Studio版本插件 下载地址

Android Studio-> 菜单栏 -> File -> Settings -> Plugins

选择Install plugin from disk -> 选择已下载的Godeyes_Android_Vx.x_(for_AndroidStudio).zip -> OK -> 安装完成 -> 重启

Project视图 -> 鼠标右键 -> Run Godeyes -> 生成报告

godeyes

godeyes

参考资料

2.4 Infer

注意:

仅支持 Mac 和 Linux 环境

需要Python 且 Python >= 2.7

使用方法

cd {项目的根目录}

./gradlew clean

infer -- ./gradlew build

一段时间后会在项目的根目录下生成infer-out这个文件夹,里面的bugs.txt文档里记录的就是扫描出的问题。

参考资料

3. 疑问解答

3.1 Android Studio 按照教程安装完Godeyes后扫描项目发现没有得到的报告没有任何错误,说明项目没有任何问题么?

不一定。Godeyes插件使用前,需要设置输出报告类型,若都两种类型都没选择,则生成的html报告中就会是0错误。如果这里也设置了但是html报告中还是0个错误则说明你的代码没有问题。

godeyes bug

3.2 Android Lint 工具检查的项目太多了,只关注error就可以了吧?

并不是,Android Lint 检查项目繁琐是由于他自身也集成了一些检查工具。例如FindBugs,单独用Findbugs检查的内容基本都涵盖在了 Android Lint检查的 Probable bugs 分组中,但Android Lint 只将这些错误视为warning,而在FindBugs则可能是Scary(严重问题)的,所以除了error,warning也是必须关注的。

android静态代码扫描,Android 静态代码扫描流程及工具说明相关推荐

  1. android静态代码扫描,android 静态代码扫描

    开始做这样一个东西是为了帮助开发减少代码方面的问题,提高代码质量,减小以后上线的风险.前面看了 360 的那个静态代码扫描感觉很强大,但目前没这实力去做成这样,希望早日开源,多多学习.所以就先用开源的 ...

  2. java 静态扫描_静态代码扫描工具 – (八)- 扫描Java项目

    静态代码扫描工具 – (八)- 扫描Java项目 1.准备好Java项目代码 只要是java语言实现的项目均可. 比如,自动化测试的代码,测试平台等均可以. 本次案例,使用java语言实现的测试平台来 ...

  3. android 代码打开nfc,android-NFC标签扫描仅触发我的应用程序启动

    我有一个可扫描NFC标签,从标签收集数据并将该数据发送到服务器的应用程序.标签上的数据采用以下格式: 1,3,30012,somebodys name 这些标签放置在客户的房屋中,以供护理人员扫描.每 ...

  4. 【Android NDK 开发】在 C 代码中获取 Android 系统信息 ( NDK 项目创建 | NDK 配置 | 获取 Android 系统版本号 )

    文章目录 I . 创建 NDK 项目 II . NDK 项目 相关配置 III . NDK 中获取 Android 版本号 IV . 使用 __system_property_get 可获取的参数 I ...

  5. Android系统性能优化(59)----代码、图片和布局优化

    Android优化系列--代码.图片和布局优化 这篇文章分为三个部分代码优化.图片优化.布局优化,尽量每个方法都写了小的Demo! 代码优化:不要做多余的工作,尽量避免次数过多的内存的分配,(需要对a ...

  6. android 代码浅黄色,Android工程中让人很不爽的“黄色警告”

    一些黄色警告 在XML中: 警告信息:[I18N] Hardcoded string "Button" , should use @string resource 意思大概是: 按 ...

  7. 代码扫描 | 把控代码质量的利器

    本文作者:潘金赤 -- CODING 产品总监 腾讯云研发平台负责人,十年研发能效建设经验 CODING 代码扫描产品负责人 有位小伙子在办公大楼门口抽烟,一位路人经过他的身边对他说:"你知 ...

  8. 好东西(Android开发人员不得不收集的代码)

    各种帮助类汇总:https://github.com/Blankj/AndroidUtilCode 常用的 ios 风格 dialog 和 meterial design 风格的 dialog:htt ...

  9. Android应用逆向——分析反编译代码之大神器

    如果说使用dex2jar和JD-GUI获得了一个APP反编译后的JAVA代码,再结合smali代码调试器来进行调试还不够爽,不够畅快的话,下面将介绍一个帮助分析代码执行流程的大神器.这个神器优点很多, ...

  10. Android开发人员不得不收集的代码

    各种帮助类汇总:https://github.com/Blankj/AndroidUtilCode 常用的 ios 风格 dialog 和 meterial design 风格的 dialog:htt ...

最新文章

  1. 用C语言解“爬动的蠕虫”题
  2. Android 中ContentProvider和Uri详解
  3. 税务计算机网络管理制度,税务系统电子数据处理管理办法(试行)
  4. Spring Cloud综合实战 - 基于TCC补偿模式的分布式事务
  5. R语言学习 - 图形设置中英字体
  6. Lotus,协作领域的常青树
  7. javascript 正则
  8. 一片文章教你如何做前端笔记。适合前端人员的笔记软件
  9. 测量学—误差理论与测量平差基础
  10. 软件开发方法 --- 结构化方法
  11. ThoughtWorks数据智能读书雷达
  12. 系统无法以在此计算机上安装,windows无法完成安装若要在此计算机上安装怎么办...
  13. margin-top传递问题
  14. postman一直sending 常见问题
  15. Golang 正则表达式判断手机号或身份证
  16. 多线程---和尚吃馒头问题
  17. 你公司哪个部门是“老大”?
  18. sumo笔记(三)——让小车跑起来(rou文件的生成)
  19. K210 Mx-yolov3模型训练和物体识别
  20. 制作chm文件搜索时总提示找不到主题的问题

热门文章

  1. 单表有父子关系,已知一个id,得到子级、孙级、曾孙级。。。
  2. NOMSQL数据库之Mongodb
  3. python123《python语言程序设计》程序设计题第一周第二周第三周第四周第五周
  4. Leetcode May Challenge - 05/07: Cousins in Binary Tree(Python)
  5. mysql查询18至28岁的人,MariaDB第三章(select)基本查询
  6. Python类别变量处理
  7. OpenBLAS项目与矩阵乘法优化 | AI 研习社
  8. 2018百度秋招一面/二面/三面
  9. 中国磷酸市场应用现状规模与需求前景预测报告2022-2028年
  10. python循环体执行的次数与其他不同的是_下面的Python循环体的执行次数与其他不同的是()...