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

#### 问题现象

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

#### 背景知识

1.  应用中的Web组件运行时，系统会为之分配一个“Render Process”进程，用于渲染。参考文档[进程模型](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/process-model-stage)。
2.  WebView是多渲染进程的，当一个Web应用打开多个页面后，每个页面都有一个渲染进程。
3.  在ArkWeb渲染子进程异常退出导致页面卡死后，应用可通过监听[onRenderExited](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-basic-components-web-events#onrenderexited9)事件来获取具体的退出原因[RenderExitReason](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-basic-components-web-e#renderexitreason9)，并在异常回调中根据退出的具体原因，执行相应的异常处理。

#### 问题定位

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](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-basic-components-web-events#onrenderexited9)事件来获取具体的退出原因[RenderExitReason](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-basic-components-web-e#renderexitreason9)，并在异常回调中根据退出的具体原因，执行相应的异常处理。

使用本例前，请先获取网络权限：[ohos.permission.INTERNET](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/permissions-for-all#ohospermissioninternet)。

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;
        })
    }
  }
}