目录

应用启动时长时间白屏后启动失败

问题现象

应用启动加载首页,首页长时间白屏,启动失败。

背景知识

  1. 应用中的Web组件运行时,系统会为之分配一个“Render Process”进程,用于渲染。参考文档进程模型。
  2. WebView是多渲染进程的,当一个Web应用打开多个页面后,每个页面都有一个渲染进程。
  3. 在ArkWeb渲染子进程异常退出导致页面卡死后,应用可通过监听onRenderExited事件来获取具体的退出原因RenderExitReason,并在异常回调中根据退出的具体原因,执行相应的异常处理。

问题定位

  1. 查看faultlogger目录,没有和应用相关的appfreeze日志,应用没有发生卡死。
  2. 查看hilog日志,由于卡死的界面采用的是Web组件,搜索关键字应用包名:Render,ArkWeb渲染子进程的进程id是35580。
    06-27 14:20:09.482 35580     1 I C04501/应用包名:render/cef: [nodict][frame_impl.cc:964] UpdatePixelRatio in render side SetPixelRatio:3
    06-27 14:20:09.483 35580     1 W C04501/应用包名:render/chromium: [nodict][html_document_parser.cc:196] OptimizeParserBudget set enable: 0
    06-27 14:20:09.493 35580     1 I C04501/应用包名:render/chromium: [nodict][scrollable_area.cc:678] ScrollableArea::SetScrollbarOverlayColorTheme scrollbar color is RGB:0x18, 0x24, 0x31
    06-27 14:20:09.493 35580     1 I C04501/应用包名:render/chromium: [nodict][page_scale_constraints.cc:85] FitToContentsWidth: compare the minimum_scale(0.25) and (1086/2940)
    06-27 14:20:09.529 35580     1 W C04501/应用包名:render/chromium: [nodict][render_frame_impl.cc:4039] event_message: content load finished, routing_id: 1, url: ***
  3. 过滤包含关键字ProcMgr的日志,ArkWeb渲染子进程35580在创建2s后就退出了。
    06-27 14:20:09.239   726 34770 I C01707/concurrent_task_service/CONCUR: [ProcMgr] process 35580 create
    06-27 14:20:09.239   726 34770 I C01707/concurrent_task_service/CONCUR: [ProcMgr] auth status 5 for pid 35580, ret = 0
    06-27 14:20:11.519   726 34770 I C01707/concurrent_task_service/CONCUR: [ProcMgr] process 35580 died
  4. 搜索关键字exitReason,ArkWeb渲染子进程35580进程退出的原因是发生了崩溃。
    06-27 14:20:11.570 35454 35454 I C04500/应用包名/chromium: [nodict][child_process_launcher_helper_linux.cc:277] GetTermination known_dead pid: 35580 exitStatus: 139 exitReason: process crashed
    06-27 14:20:11.572 35454 35454 I C04500/应用包名/cef: [nodict][render_widget_host_view_osr.cc:569] ReleaseCompositor
    06-27 14:20:11.572 35454 35454 I C04500/应用包名/cef: [nodict][render_widget_host_view_osr.cc:575] ReleaseCompositor, widget = 1
    06-27 14:20:11.580 35454 35576 I C04500/应用包名/chromium: [nodict][external_begin_frame_source_ohos.cc:98] ExternalBeginFrameSourceOHOS destructor!!!
    06-27 14:20:11.581 35454 35454 I C04500/应用包名/chromium: [nodict][nweb_handler_delegate.cc:1506] NWebHandlerDelegate::OnLargestContentfulPaint
    06-27 14:20:11.581 35454 35454 I C0391B/应用包名/AceWeb: [(100000:100000:scope)] WebDelegate::OnLargestContentfulPaint, web id = 1
    06-27 14:20:11.581 35454 35454 I C04500/应用包名/chromium: [nodict][nweb_handler_delegate.cc:1901] NWebId: 1 render process exit, reason = 2 reason info = process crashed

分析结论

应用渲染子进程发生崩溃后异常退出,导致启动长时间白屏。

修改建议

监听onRenderExited事件来获取具体的退出原因RenderExitReason,并在异常回调中根据退出的具体原因,执行相应的异常处理。

使用本例前,请先获取网络权限:ohos.permission.INTERNET。

import { webview } from '@kit.ArkWeb';

@Entry
@Component
struct WebComponentPage {
  needReloadWhenVisible: boolean = false; // Web组件不可见时render退出后阻止重新加载页面,在可见时重新加载页面。
  webIsVisible: boolean = false; // 判断Web组件是否可见。
  // 此处是将子进程异常崩溃和其它异常原因做了区分,应用开发者可根据实际业务特点,细化对应异常的处理策略。
  renderReloadMaxForCrashed: number = 5; // 设置因为异常崩溃后重新加载的最大重试次数,应用可根据业务特点,自行设置试错上限。
  renderReloadCountForCrashed: number = 0; // 异常崩溃后重新加载的次数。
  renderReloadMaxForOthers: number = 10; // 设置因为其它异常原因退出的最大重试次数,应用可根据业务特点,自行设置试错上限。
  renderReloadCountForOthers: number = 0; // 其它异常原因退出后重新加载的次数。
  // 创建Web组件。
  controller: webview.WebviewController = new webview.WebviewController();
  // 指定加载的页面,此处替换成正确的URL地址。
  url: string = 'www.example.com';

  build() {
    Column() {
      Web({ src: this.url, controller: this.controller })
        .onVisibleAreaChange([0, 1.0], (isVisible) => {
          this.webIsVisible = isVisible;
          if (isVisible && this.needReloadWhenVisible) { // Web组件可见时重新加载页面。
            this.needReloadWhenVisible = false;
            this.controller.loadUrl(this.url);
          }
        })
        .fileAccess(false)
        .geolocationAccess(false)
        .backgroundColor(Color.Gray)
        // 应用监听渲染子进程异常退出回调,并进行异常处理。
        .onRenderExited((event) => {
          if (!event) {
            return;
          }
          if (event.renderExitReason === RenderExitReason.ProcessCrashed) {
            if (this.renderReloadCountForCrashed >= this.renderReloadMaxForCrashed) {
              // 设置重试次数上限保护,避免必现问题导致页面被循环加载。
              return;
            }
            console.info(`renderReloadCountForCrashed: ${this.renderReloadCountForCrashed}`);
            this.renderReloadCountForCrashed++;
          } else {
            if (this.renderReloadCountForOthers >= this.renderReloadMaxForOthers) {
              // 设置重试次数上限保护,避免必现问题导致页面被循环加载。
              return;
            }
            console.info(`renderReloadCountForOthers: ${this.renderReloadCountForOthers}`);
            this.renderReloadCountForOthers++;
          }
          if (this.webIsVisible) {
            // Web组件可见则立即重新加载。
            this.controller.loadUrl(this.url);
            return;
          }
          // Web组件不可见时不立即重新加载。
          this.needReloadWhenVisible = true;
        })
    }
  }
}