Page 139 - 《软件学报》2026年第6期
P. 139

2458                                                       软件学报  2026  年第  37  卷第  6  期


                  1   研究动机示例

                    AnkiDroid  是一款安卓开源学习软件, 旨在帮助用户高效记忆内容, 提供卡片自定义、同步功能以及多种学习
                 模式. 图  2(a) 展示了与图   1  中堆栈跟踪对应的触发       AnkiDroid  的#4586  崩溃的事件序列: 用户打开应用后, 点击
                 “Add”按钮进入添加笔记页面, 随后点击“Attach mutimedia content to the Front filed”按钮, 选择“CAMERA”添加图
                 片时应用发生崩溃. 在对应用代码进行分析后发现, 在步骤                  5  中点击“CAMERA”按钮后, 图     2(b) 所示的事件处理
                 器  (onClick) 创建了隐式相机   Intent 对象以启动相机应用并捕获图片. 该          Intent 对象包含拍照后图片的保存位置
                 (第  3–8  行), 并通过  Android  系统提供的启动活动方法与相机应用通信         (第  9  行), 触发相机启动. 然而, 为防止隐私
                 泄露和安全风险, 自安卓       7.0 (Nougat) 起, 系统限制了应用间直接通过       file://URI 直接共享文件. 当应用尝试将本地
                 文件路径   (file://URI) 暴露给其他应用时, 会触发     android.os.FileUriExposed Exception  异常. 这一问题, 如图  1  中堆
                 栈跟踪所示, 是由于违反安卓系统安全策略而引发的崩溃错误.

                 (a)  Step 1: 点击“Add”  Step 2: 点击“Add”  Step 3: 点击“Attach multimedia   Step 4: 点击“Add image”  Step 5: 点击“CAMERA”  崩溃
                                                 content to the Front field ”












                                                                                      multimediacard.activity.
                             DeckPicker                    NoteEditor                MultimediaEditFieldActivity
                 (b)
                           @Override public void onClick(View v) {
                                       ...
                            Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");
                                       ...
                            try {
                             File image = File.createTempFile("img_", ".jpg", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)) ;
                             this.this$0.mTempCameraImagePath = image.getPath();
                                           cameraIntent.putExtra("output", Uri.fromFile(image));
                             this.this$0.mActivity.startActivityForResult(cameraIntent, 2);
                                     } catch (IOException e) {
                                        e.printStackTrace();  / / 处理文件创建失败
                                     }
                            ...
                          }
                    图 2 AnkiDroid  应用问题  ID 4586  崩溃对应的复现步骤和点击“CAMERA”按钮后创建的隐式               Intent 实例

                    以图  2  所示的  AnkiDroid  应用中的崩溃为例, 使用传统的自动化测试工具             Monkey [17] 、APE [18] 及代表性的崩
                                  [9]
                 溃复现工具    ReCDroid 、ReproBot 和 [8]  CrashTranslator [14] 进行了  30 min  的测试, 其中  ReCDroid  和  ReproBot 以崩
                 溃报告标题作为输入, CrashTranslator 以堆栈跟踪作为输入. 结果显示, 只有             ReCDroid  成功触发了崩溃, 复现时间
                 接近  5 min. 分析表明, 由于  AnkiDroid  应用的  GUI 页面包含大量控件, 且触发崩溃需要严格的事件顺序, 上述工
                 具难以高效触发该崩溃. 具体来说, Monkey          生成的事件完全随机, 无法按照特定的逻辑顺序执行                 GUI 操作; APE
                 则在与崩溃无关的路径上消耗了大量测试资源, 导致效率低下; ReCDroid                   基于   813  个缺陷报告语料库构建了       22
                 种语法模式, 包括动作、目标控件及输入内容等要素提取模板. 该策略依赖明确的操作描述和完整句法结构. 对于
                 图  1  中所示崩溃报告标题“Crash on add picture from camera on Android 7”, 由于描述简短且未明确指示动作与控件
                 关系  (如缺少“click camera”等指令), ReCDroid  难以通过预定义语法模式提取必要的“add”和“camera”关键操作信
                 息.然而, 该方法通过动态事件序列推导补全缺失步骤, 从而成功触发崩溃; ReproBot 则不依赖于固定的语法模式,
                 而采用句法成分分析和连词语义推理提取操作元素, 并根据隐含的时间关系推断操作执行顺序. 在该示例中,
   134   135   136   137   138   139   140   141   142   143   144