当前位置: 首页 > wzjs >正文

电影资源网站怎么做的手表之家官网

电影资源网站怎么做的,手表之家官网,国际热点事件,网络游戏公司排行榜前十名3.2.3 Android App动态调用链路 在Android应用中,动态调用链路指的是应用在运行时的调用路径。这通常涉及到方法调用的顺序和调用关系,特别是在应用的复杂逻辑中,理解这些调用链路对于调试和性能优化非常重要。 1,动态调用链路获…

3.2.3 Android App动态调用链路

在Android应用中,动态调用链路指的是应用在运行时的调用路径。这通常涉及到方法调用的顺序和调用关系,特别是在应用的复杂逻辑中,理解这些调用链路对于调试和性能优化非常重要。

1,动态调用链路获取方法

要获取Android应用的动态调用链路,可以使用以下几种方法:

(1)使用调试工具:

(2)使用日志:

(3)使用性能分析工具:

(4)使用第三方工具:

(5)动态分析工具:

(6)字节码插桩:

    每种方法都有其优缺点,选择合适的方法取决于你的具体需求和应用的复杂性。如果你只是想简单地查看某个功能的调用链路,使用调试工具或日志可能是最简单的选择;如果需要更深入的分析,Profiler或第三方工具可能更合适。

2,动态调用链路的使用

      静态调用链路主要用来分析需求开发的影响范围,界定测试范围。动态调用链路主要和用例关联起来,需要知道哪些用例执行过程中,会调用哪些类或是函数,如下图所示:

通过获取用例的动态调用链路后,可以做如下事情:

  • 过滤用例执行中的前置和后置步骤,减少用例关联的代码;
  • 通过路径覆盖,推荐用例,用最小的用例集来覆盖最大的功能面;
  • 用例执行失败,问题定位与修复。

Android App的动态调用链路采取插桩方式进行记录,由于jacoco Android插件没有开源,可以借助于服务端的jacoco来开发新的插件来实现,主要流程如下:

一,Trace插件开发

1,保存类函数对应关系

     借助于jacoco插件的核心功能,对项目代码进行插桩,对每一个类和函数进行插桩,记录类的classid, methodid,执行次序和执行时间。插桩的过程中,将classid, 类名,methodid,函数名与参数等信息记录到class-method-map.txt文件中,打包的时候会将文件生成保存到工作目录中。

public class JacocoPlugin extends Transform implements Plugin<Project> {.....@Override
public void transform(TransformInvocation transformInvocation)throws TransformException, InterruptedException, IOException {super.transform(transformInvocation);System.out.println("AutoTest " + project.getName() + "," + project.getDisplayName() + "," + project.getPath());System.out.println("--------------------------");long start = System.currentTimeMillis();long copyCost = 0;long instrumentCost = 0;long copyDirCost = 0;Collection<TransformInput> inputs = transformInvocation.getInputs();TransformOutputProvider outputProvider = transformInvocation.getOutputProvider();for (TransformInput input : inputs) {//对项目中的jar包进行处理for (JarInput jarInput : input.getJarInputs()) {String jarName = jarInput.getName();File dest = outputProvider.getContentLocation(jarName,jarInput.getContentTypes(), jarInput.getScopes(), Format.JAR);//暂时不对app应用引用的jar包进行注入,防止因引用包造成二次注入 2024013if (filterJar(jarInput, sKwaiTestConfig) && project.getPlugins().hasPlugin("com.android.library")) {System.out.println("process jar is:" + jarName);System.out.println("process jar abspath is :" + jarInput.getFile().getAbsolutePath());sKwaiTestConfig.classJars.add(jarInput.getFile().getAbsolutePath());long tStart = System.currentTimeMillis();transformJar(jarInput, dest, jarName);long tEnd = System.currentTimeMillis();instrumentCost += (tEnd - tStart);} else {long cStart = System.currentTimeMillis();FileUtils.copyFile(jarInput.getFile(), dest);long cEnd = System.currentTimeMillis();copyCost += (cEnd - cStart);System.out.println("App Project " + project.getName() + "," + project.getDisplayName() + "," + project.getPath() + " not transform jar files!");}//System.out.println("transform jar的位置:"+dest.getAbsolutePath());}long dStart = System.currentTimeMillis();for (DirectoryInput directoryInput : input.getDirectoryInputs()) {File dest = outputProvider.getContentLocation(directoryInput.getName(),directoryInput.getContentTypes(), directoryInput.getScopes(), Format.DIRECTORY);if (filterDir(directoryInput, sKwaiTestConfig)) {String relatePath = directoryInput.getFile().getAbsolutePath();System.out.println("process dir file is:" + relatePath);sKwaiTestConfig.classDirs.add(relatePath);Instrumenter instrumenter = new Instrumenter(new OfflineInstrumentationAccessGenerator());transformDirectory(directoryInput.getFile(), dest, relatePath, instrumenter);} else {FileUtils.copyDirectory(directoryInput.getFile(), dest);}//System.out.println("transform 类的位置:" + dest.getAbsolutePath());}long dEnd = System.currentTimeMillis();copyDirCost = dEnd - dStart;}if (FLAG.decrementAndGet() == 0) {if (!TraceMethodVisitor.sMap.isEmpty()) {Utils.writeTraceMap(sTraceMapPath, TraceMethodVisitor.sMap);sKwaiTestConfig.customTraceMapPath = sTraceMapPath;//清除早期的trac数据TraceMethodVisitor.sMap.clear();} else {System.out.println("TraceMethodVisitor 为空!");}String configStr = (new Gson()).toJson(sKwaiTestConfig);Utils.writeKwaiTestFile(sKwaiTestConfigPath, configStr);System.out.println("Auto test jacoco writeKwaiTestFile");}long end = System.currentTimeMillis();System.out.println("---------------Auto test jacoco transform end-----------");System.out.println("Auto test jacoco copy jar cost:" + copyCost + "ms");System.out.println("Auto test jacoco copy dir cost:" + copyDirCost + "ms");System.out.println("Auto test jacoco instrument cost:" + instrumentCost + "ms");System.out.println("Auto test jacoco transform cost:" + (end - start) / 1000 + "s");System.out.println("---------执行 transform---------------");
}
.....
}

2,记录用例执行路径

在类函数中添加记录用例执行路径的操作,如:新建CSTraceHelper类

public class CSTraceHelper {....private Thread sConsumer = new Thread(() -> {if (sFirstInit) {sFirstInit = false;} else {return;}if (sStoragePath == null) {return;}for (; ; ) {flushTraceData();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});public static void flushTraceData() {if (sStoragePath != null && (!sKDSStore.isEmpty() || !sNativeStore.isEmpty())) {appendDataToFile();}
}
/**
将trace信息写入文件
**/
private static void appendDataToFile() {synchronized (sNativeStore) {FileWriter fileWriter = null;BufferedWriter bw = null;try {File dataDir = new File(sStoragePath);if (!dataDir.exists()) {dataDir.mkdirs();}File dataFile = new File(dataDir, TRACE_FILE_NAME);if (!dataFile.exists()) {dataFile.createNewFile();}Log.d(TAG, "Trace文件:" + dataFile.getAbsolutePath());fileWriter = new FileWriter(dataFile, true);bw = new BufferedWriter(fileWriter);Long value = sNativeStore.poll();HashMap<String, TraceDataSimple> map = new HashMap<>();while (value != null) {// 从 long 值中恢复三个 int 值int classId = (int) (value >> 42);int methodId = (int) ((value >> 21) & 0x1FFFFF);int line = (int) (value & 0x1FFFFF);//Log.d(TAG,"appendDataToFile cid:"+classId+",mId:"+methodId+",line:"+line+",value="+value);String key = classId + "" + methodId;if (map.containsKey(key)) {map.get(key).lines.add(String.valueOf(line));} else {TraceDataSimple method = new TraceDataSimple();method.tName = "t";method.timeMillis = System.currentTimeMillis();method.cid = classId;method.mid = methodId;method.lines.add(String.valueOf(line));map.put(key, method);}value = sNativeStore.poll();}Iterator<Map.Entry<String, TraceDataSimple>> it = map.entrySet().iterator();while (it.hasNext()) {bw.write(it.next().getValue().toSimpleString());}bw.flush();} catch (IOException e) {Log.d(TAG, "appendDataToFile catch error:" + e.getMessage());e.printStackTrace();} finally {try {if (bw != null) {bw.close();}if (fileWriter != null) {fileWriter.close();}} catch (IOException e) {Log.d(TAG, "appendDataToFile finally error:" + e.getMessage());e.printStackTrace();}}Log.d(TAG,"Trace 数据写入完成:"+sStoragePath);}
}
/*** 重新注入项目* @param cId 类ID* @param mId 方法ID* @param line 行号*/
public static void injectTcEp(long cId, int mId, int line) {// Log.d(TAG,"sStoragePath="+sStoragePath+",sNeedInject="+sNeedInject);if (sStoragePath != null && sNeedInject) {// 将三个 int 值存储到一个 long 值中long value = ((long) cId << 42) | ((long) mId << 21) | (long) line;Log.d(TAG,"Inject cid:"+cId+",mId:"+mId+",line:"+line+",value="+value);sNativeStore.offer(value);}
}
......
}

同时在Android插件JacocoPlugin的TraceMethodVisitor类中添加给函数注入记录trace信息的操作

public class TraceMethodVisitor extends MethodVisitor {......private void injectMethod() {mv.visitLdcInsn(classID);mv.visitLdcInsn(id);mv.visitLdcInsn(line);mv.visitMethodInsn(INVOKESTATIC, "com/kwai/test/core/CSTraceHelper", "injectTcEp","(JII)V", false);
}
.......
}

执行打包命令

./gradlew upload

将会在指定的目录下,生成新插件的所有包。

二,新插件使用

      在要关联用例的App中,添加新的jacoco插件,打包后就会自动对函数中的类,函数进行插桩。如果想同时采集覆盖率数据,控制好相关的开关即可。打包完成后做如下操作:

1,将打包后的class文件上传到指定位置,如精准测试平台,在生成覆盖率报告时候要用到。

2,将生成的class-method-map.txt文件上传到精准测试平台,解析用例与代码的关联关系时需要查询类和函数信息。

C: com.gavin.asmdemo.MainActivity 1 com/gavin/asmdemo/MainActivity.java
M: onCreate(android.os.Bundle) 0 12
M: toSecond(android.view.View) 1 18
M: toThrid(android.view.View) 2 24
M: onStop() 3 8
M: onStart() 4 8
C: com.gavin.asmdemo.ThridActivity 2 com/gavin/asmdemo/ThridActivity.java
M: onCreate(android.os.Bundle) 0 14
M: toShow(android.view.View) 1 19
M: thToIndexPage(android.view.View) 2 26
M: onStop() 3 10
M: onStart() 4 10
C: com.gavin.asmdemo.BaseActivity 3 com/gavin/asmdemo/BaseActivity.java
M: onCreate(android.os.Bundle) 0 17
M: onStart() 1 24
M: onStop() 2 32
C: com.gavin.asmdemo.SecondActivity 4 com/gavin/asmdemo/SecondActivity.java
M: onCreate(android.os.Bundle) 0 11
M: seToThrid(android.view.View) 1 16
M: toIndexPage(android.view.View) 2 21
M: onStop() 3 7
M: onStart() 4 7

3,在测试需求时,根据需求,上传覆盖率,trace信息文件。

4,生成覆盖率报告时,解析trace信息,记录追溯关系。

5,根据业务特点,过滤一下trace信息,就可以拿到用例与代码的精准关联关系。


文章转载自:

http://PDsGCgXS.jjzbx.cn
http://k8ahMNqJ.jjzbx.cn
http://JpczxM6T.jjzbx.cn
http://dxS1rMcC.jjzbx.cn
http://rbrRPShY.jjzbx.cn
http://fZ12LVL6.jjzbx.cn
http://skvMsyWK.jjzbx.cn
http://D24FKtbW.jjzbx.cn
http://SZIZbSLr.jjzbx.cn
http://XRKhkt39.jjzbx.cn
http://5SSVbmtv.jjzbx.cn
http://idbiIa6j.jjzbx.cn
http://WqVNT0Kv.jjzbx.cn
http://hTZPFwyf.jjzbx.cn
http://OiGZznUr.jjzbx.cn
http://QTeCysZk.jjzbx.cn
http://AZJHTdI4.jjzbx.cn
http://zuBBMXnf.jjzbx.cn
http://PJsJYvvw.jjzbx.cn
http://3DuQzYpm.jjzbx.cn
http://BfJmXwZE.jjzbx.cn
http://ruGr9al1.jjzbx.cn
http://azFQzMYG.jjzbx.cn
http://5zGLBcOk.jjzbx.cn
http://ZxLebcUf.jjzbx.cn
http://wJy71oA8.jjzbx.cn
http://YQLt1yxc.jjzbx.cn
http://8rfO1UKu.jjzbx.cn
http://SG51zjj8.jjzbx.cn
http://CfiWlcFD.jjzbx.cn
http://www.dtcms.com/wzjs/708807.html

相关文章:

  • 福州做网站优化电商运营培训班
  • 北京网站建设公司网站优化资讯百科网站推广
  • 建设一个网站app需要多少钱wordpress的搭建教程 pdf
  • 网站域名优势自己建设个人网站要花费多少
  • 苏州建设局统计网站网易企业邮箱密码忘记了怎么找回密码
  • 网站排名套餐互联网站管理工作细则
  • 秀网站模板小游戏入口免费游戏
  • 电商网站设计论文图片加文字在线制作
  • 专业做消防工程师的正规网站网店推广有哪些
  • 合肥高端网站建设费用安卓开发工具下载
  • 哪个网站学习做辅助 天堂资源官网在线资源
  • 网站风格配置怎么做网站关闭模板
  • iis7.5网站配置网络服务费要交印花税吗
  • 网站多级栏目wordpress过滤敏感
  • 天水市建设银行官方网站网络营销品牌策划优化
  • 河南网站排名优化价格wordpress恢复密码
  • 湛江模板建站多少钱英文网站 常用字体
  • 无锡专业网站wp网站做企业站好不好
  • 平台型网站如何推广北京电商平台网站建设
  • 如何发布网站到域名电子商务平台的功能有哪些
  • 私自建设网站淘宝联盟建网站
  • 网站建设 客户评价科技网站设计公司排行榜
  • 厦门做企业网站自媒体怎么注册账号
  • 做网站教材wordpress网站页面打开很慢
  • 舟山市城市建设档案馆网站提供衡水网站建设
  • 后端开发网站做一些什么wordpress设置系统邮箱
  • 做漆包线的招聘网站外企网站建设
  • 中国人自己的空间站wordpress怎么添加管理员
  • 有没有小学生做兼职的网站wordpress $wp
  • 网站流量如何做济南建设企业网站