From b38e990d13b9c898c6f76320bac1ebc85fb825e2 Mon Sep 17 00:00:00 2001 From: siguangli Date: Wed, 27 Mar 2024 14:09:34 +0800 Subject: [PATCH] feat(android): support fcp monitor (#3796) * feat(android): support fcp monitor * fix(android): rename to PAINT_TYPE_KEY --------- Co-authored-by: maxli --- .../hippy-react-demo/src/pages/gallery.jsx | 1 + .../hippy-vue-demo/src/pages/menu.vue | 2 +- .../hippy-vue-next-demo/src/pages/menu.vue | 2 +- .../performance_navigation_timing.h | 3 + .../performance_navigation_timing_module.cc | 1 + .../cpp/include/connector/js_driver_jni.h | 4 +- .../js/src/main/cpp/src/js_driver_jni.cc | 28 ++++- .../com/openhippy/connector/JsDriver.java | 12 +- .../mtt/hippy/HippyEngineManagerImpl.java | 45 +++---- .../monitor/DefaultEngineMonitorAdapter.java | 34 ++---- .../monitor/HippyEngineMonitorAdapter.java | 13 +- .../mtt/hippy/bridge/HippyBridgeImpl.java | 3 - .../hippy/bridge/HippyBridgeManagerImpl.java | 26 ++-- .../tencent/mtt/hippy/utils/TimeMonitor.java | 113 +++++++++++------- .../com/tencent/mtt/hippy/HippyRootView.java | 2 +- .../com/tencent/renderer/FrameworkProxy.java | 4 +- .../com/tencent/renderer/NativeRender.java | 5 +- .../com/tencent/renderer/NativeRenderer.java | 41 ++++++- 18 files changed, 208 insertions(+), 131 deletions(-) diff --git a/driver/js/examples/hippy-react-demo/src/pages/gallery.jsx b/driver/js/examples/hippy-react-demo/src/pages/gallery.jsx index b44b85f146b..ed57c079124 100644 --- a/driver/js/examples/hippy-react-demo/src/pages/gallery.jsx +++ b/driver/js/examples/hippy-react-demo/src/pages/gallery.jsx @@ -188,6 +188,7 @@ export class Gallery extends Component { renderRow={this.renderRow} getRowType={this.getRowType} getRowKey={this.getRowKey} + paintType="fcp" /> ); } diff --git a/driver/js/examples/hippy-vue-demo/src/pages/menu.vue b/driver/js/examples/hippy-vue-demo/src/pages/menu.vue index bf8032a3372..cafb229f430 100644 --- a/driver/js/examples/hippy-vue-demo/src/pages/menu.vue +++ b/driver/js/examples/hippy-vue-demo/src/pages/menu.vue @@ -31,7 +31,7 @@
  • -

    +

    终端组件 Demos

  • diff --git a/driver/js/examples/hippy-vue-next-demo/src/pages/menu.vue b/driver/js/examples/hippy-vue-next-demo/src/pages/menu.vue index 0cd40adb689..0de84784e3e 100644 --- a/driver/js/examples/hippy-vue-next-demo/src/pages/menu.vue +++ b/driver/js/examples/hippy-vue-next-demo/src/pages/menu.vue @@ -31,7 +31,7 @@
  • -

    +

    终端组件 Demos

  • diff --git a/driver/js/include/driver/performance/performance_navigation_timing.h b/driver/js/include/driver/performance/performance_navigation_timing.h index 1b652bc56a8..1374e2a85cf 100644 --- a/driver/js/include/driver/performance/performance_navigation_timing.h +++ b/driver/js/include/driver/performance/performance_navigation_timing.h @@ -64,6 +64,8 @@ class PerformanceNavigationTiming : public PerformanceEntry { DEFINE_SET_AND_GET_METHOD(HippyDomEnd, TimePoint, hippy_dom_end_) DEFINE_SET_AND_GET_METHOD(HippyFirstFrameStart, TimePoint, hippy_first_frame_start_) DEFINE_SET_AND_GET_METHOD(HippyFirstFrameEnd, TimePoint, hippy_first_frame_end_) + DEFINE_SET_AND_GET_METHOD(HippyFirstContentfulPaintEnd, TimePoint, hippy_first_contentful_paint_end_) + #undef DEFINE_SET_AND_GET_METHOD inline const std::vector& GetBundleInfoArray() const { @@ -86,6 +88,7 @@ class PerformanceNavigationTiming : public PerformanceEntry { TimePoint hippy_dom_end_; TimePoint hippy_first_frame_start_; TimePoint hippy_first_frame_end_; + TimePoint hippy_first_contentful_paint_end_; }; } diff --git a/driver/js/src/modules/performance/performance_navigation_timing_module.cc b/driver/js/src/modules/performance/performance_navigation_timing_module.cc index 017c281f77d..5b5cade5cb1 100644 --- a/driver/js/src/modules/performance/performance_navigation_timing_module.cc +++ b/driver/js/src/modules/performance/performance_navigation_timing_module.cc @@ -99,6 +99,7 @@ std::shared_ptr> RegisterPerformanceN ADD_PROPERTY(hippy_dom_end, "hippyDomEnd", GetHippyDomEnd) ADD_PROPERTY(hippy_first_frame_start, "hippyFirstFrameStart", GetHippyFirstFrameStart) ADD_PROPERTY(hippy_first_frame_end, "hippyFirstFrameEnd", GetHippyFirstFrameEnd) + ADD_PROPERTY(hippy_first_contentful_paint_end, "hippyFirstContentfulPaintEnd", GetHippyFirstContentfulPaintEnd) #undef ADD_PROPERTY PropertyDefine bundle_info; diff --git a/framework/android/connector/driver/js/src/main/cpp/include/connector/js_driver_jni.h b/framework/android/connector/driver/js/src/main/cpp/include/connector/js_driver_jni.h index 2f3b8b3b28a..97cb14f0644 100644 --- a/framework/android/connector/driver/js/src/main/cpp/include/connector/js_driver_jni.h +++ b/framework/android/connector/driver/js/src/main/cpp/include/connector/js_driver_jni.h @@ -86,7 +86,9 @@ void SetDomManager(JNIEnv* j_env, void OnNativeInitEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong startTime, jlong endTime); -void OnFirstFrameEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong time); +void OnFirstPaintEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong time); + +void OnFirstContentfulPaintEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong time); void OnResourceLoadEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jstring j_uri, jlong j_start_time, jlong j_end_time, jlong j_ret_code, jstring j_error_msg); diff --git a/framework/android/connector/driver/js/src/main/cpp/src/js_driver_jni.cc b/framework/android/connector/driver/js/src/main/cpp/src/js_driver_jni.cc index 9f56462191a..b3f03d58564 100644 --- a/framework/android/connector/driver/js/src/main/cpp/src/js_driver_jni.cc +++ b/framework/android/connector/driver/js/src/main/cpp/src/js_driver_jni.cc @@ -111,9 +111,14 @@ REGISTER_JNI("com/openhippy/connector/JsDriver", // NOLINT(cert-err58-cpp) OnNativeInitEnd) REGISTER_JNI("com/openhippy/connector/JsDriver", // NOLINT(cert-err58-cpp) - "onFirstFrameEnd", + "onFirstPaintEnd", "(IJ)V", - OnFirstFrameEnd) + OnFirstPaintEnd) + +REGISTER_JNI("com/openhippy/connector/JsDriver", // NOLINT(cert-err58-cpp) + "onFirstContentfulPaintEnd", + "(IJ)V", + OnFirstContentfulPaintEnd) REGISTER_JNI("com/openhippy/connector/JsDriver", // NOLINT(cert-err58-cpp) "onResourceLoadEnd", @@ -180,7 +185,7 @@ void OnNativeInitEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong sta } } -void OnFirstFrameEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong time) { +void OnFirstPaintEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong time) { auto scope = GetScope(j_scope_id); auto runner = scope->GetEngine().lock()->GetJsTaskRunner(); if (runner) { @@ -204,6 +209,23 @@ void OnFirstFrameEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong tim } } +void OnFirstContentfulPaintEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong time) { + auto scope = GetScope(j_scope_id); + auto runner = scope->GetEngine().lock()->GetJsTaskRunner(); + if (runner) { + std::weak_ptr weak_scope = scope; + auto task = [weak_scope, time]() { + auto scope = weak_scope.lock(); + if (!scope) { + return; + } + auto entry = scope->GetPerformance()->PerformanceNavigation("hippyInit"); + entry->SetHippyFirstContentfulPaintEnd(footstone::TimePoint::FromEpochDelta(footstone::TimeDelta::FromMilliseconds(time))); + }; + runner->PostTask(std::move(task)); + } +} + void OnResourceLoadEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jstring j_uri, jlong j_start_time, jlong j_end_time, jlong j_ret_code, jstring j_error_msg) { if (!j_uri) { diff --git a/framework/android/connector/driver/js/src/main/java/com/openhippy/connector/JsDriver.java b/framework/android/connector/driver/js/src/main/java/com/openhippy/connector/JsDriver.java index 954391c9d19..d61b10eb0c8 100644 --- a/framework/android/connector/driver/js/src/main/java/com/openhippy/connector/JsDriver.java +++ b/framework/android/connector/driver/js/src/main/java/com/openhippy/connector/JsDriver.java @@ -73,8 +73,12 @@ public void recordNativeInitEndTime(long startTime, long endTime) { onNativeInitEnd(mInstanceId, startTime, endTime); } - public void recordFirstFrameEndTime(long time) { - onFirstFrameEnd(mInstanceId, time); + public void recordFirstPaintEndTime(long time) { + onFirstPaintEnd(mInstanceId, time); + } + + public void recordFirstContentfulPaintEndTime(long time) { + onFirstContentfulPaintEnd(mInstanceId, time); } public void doRecordResourceLoadResult(@NonNull String uri, long startTime, long endTime, @@ -166,7 +170,9 @@ private native void callFunction(int instanceId, String action, NativeCallback c private native void onNativeInitEnd(int instanceId, long startTime, long endTime); - private native void onFirstFrameEnd(int instanceId, long time); + private native void onFirstPaintEnd(int instanceId, long time); + + private native void onFirstContentfulPaintEnd(int instanceId, long time); private native void onResourceLoadEnd(int instanceId, String uri, long startTime, long endTime, long retCode, String errorMsg); diff --git a/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java b/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java index 1507076c967..2d29585359b 100644 --- a/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java +++ b/framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java @@ -55,8 +55,6 @@ import com.tencent.mtt.hippy.utils.LogUtils; import com.tencent.mtt.hippy.utils.PixelUtil; import com.tencent.mtt.hippy.utils.TimeMonitor; -import com.tencent.mtt.hippy.utils.TimeMonitor.MonitorGroup; -import com.tencent.mtt.hippy.utils.TimeMonitor.MonitorGroupType; import com.tencent.mtt.hippy.utils.UIThreadUtils; import com.tencent.renderer.FrameworkProxy; import com.tencent.renderer.component.image.ImageDecoderAdapter; @@ -219,19 +217,23 @@ protected void onDestroyEngine() { } @Override - public void onFirstViewAdded() { - mEngineContext.getJsDriver().recordFirstFrameEndTime(System.currentTimeMillis()); - MonitorGroup monitorGroup = mEngineContext.getMonitor() - .endGroup(MonitorGroupType.LOAD_INSTANCE); - if (monitorGroup != null) { - mGlobalConfigs.getEngineMonitorAdapter() - .onLoadInstanceCompleted(mEngineContext.getComponentName(), monitorGroup); - } + public void onFirstPaint() { + mEngineContext.getJsDriver().recordFirstPaintEndTime(System.currentTimeMillis()); + mEngineContext.getMonitor().addPoint(TimeMonitor.MONITOR_GROUP_PAINT, + TimeMonitor.MONITOR_POINT_FIRST_CONTENTFUL_PAINT); + mGlobalConfigs.getEngineMonitorAdapter().onFirstPaintCompleted(mEngineContext.getComponentName()); if (mModuleListener != null) { mModuleListener.onFirstViewAdded(); } } + @Override + public void onFirstContentfulPaint() { + mEngineContext.getJsDriver().recordFirstContentfulPaintEndTime(System.currentTimeMillis()); + mEngineContext.getMonitor().endGroup(TimeMonitor.MONITOR_GROUP_PAINT); + mGlobalConfigs.getEngineMonitorAdapter().onFirstContentfulPaintCompleted(mEngineContext.getComponentName()); + } + @Override public void onSizeChanged(int rootId, int w, int h, int ow, int oh) { if (mEngineContext != null) { @@ -582,12 +584,7 @@ void notifyEngineInitialized(final EngineInitStatus statusCode, final Throwable private void onEngineInitialized(EngineInitStatus statusCode, Throwable error) { mEngineContext.getJsDriver().recordNativeInitEndTime(mInitStartTime, System.currentTimeMillis()); - MonitorGroup monitorGroup = mEngineContext.getMonitor() - .endGroup(MonitorGroupType.ENGINE_INITIALIZE); - if (monitorGroup != null) { - mGlobalConfigs.getEngineMonitorAdapter() - .onEngineInitialized(statusCode, monitorGroup); - } + mGlobalConfigs.getEngineMonitorAdapter().onEngineInitialized(statusCode); for (EngineListener listener : mEventListeners) { listener.onInitialized(statusCode, error == null ? null : error.toString()); } @@ -595,8 +592,8 @@ private void onEngineInitialized(EngineInitStatus statusCode, Throwable error) { } private synchronized void restartEngineInBackground(boolean onReLoad) { - mMonitor.startPoint(MonitorGroupType.ENGINE_INITIALIZE, - TimeMonitor.MONITOR_POINT_INIT_NATIVE_ENGINE); + mMonitor.beginGroup(TimeMonitor.MONITOR_GROUP_INIT_ENGINE); + mMonitor.addPoint(TimeMonitor.MONITOR_GROUP_INIT_ENGINE, TimeMonitor.MONITOR_POINT_INIT_NATIVE_ENGINE); if (mCurrentState == EngineState.DESTROYED) { String errorMsg = "restartEngineInBackground... error STATUS_WRONG_STATE, state=" + mCurrentState; @@ -1041,19 +1038,13 @@ public void run() { @Override public void onLoadModuleCompleted(ModuleLoadStatus statusCode, @Nullable String msg) { notifyModuleLoaded(statusCode, msg); - MonitorGroup monitorGroup = mEngineContext.getMonitor() - .endGroup(MonitorGroupType.RUN_JS_BUNDLE); - if (monitorGroup != null) { - mGlobalConfigs.getEngineMonitorAdapter() - .onLoadModuleCompleted(statusCode, mEngineContext.getComponentName(), - monitorGroup); - } + mGlobalConfigs.getEngineMonitorAdapter() + .onLoadModuleCompleted(statusCode, mEngineContext.getComponentName()); } @Override public void onLoadInstanceCompleted(long result, String reason) { - mEngineContext.getMonitor().startPoint(MonitorGroupType.LOAD_INSTANCE, - TimeMonitor.MONITOR_POINT_FIRST_FRAME); + } public void destroyBridge(boolean isReload) { diff --git a/framework/android/src/main/java/com/tencent/mtt/hippy/adapter/monitor/DefaultEngineMonitorAdapter.java b/framework/android/src/main/java/com/tencent/mtt/hippy/adapter/monitor/DefaultEngineMonitorAdapter.java index bd3b460369d..3450bf5db2d 100644 --- a/framework/android/src/main/java/com/tencent/mtt/hippy/adapter/monitor/DefaultEngineMonitorAdapter.java +++ b/framework/android/src/main/java/com/tencent/mtt/hippy/adapter/monitor/DefaultEngineMonitorAdapter.java @@ -23,46 +23,32 @@ import com.tencent.mtt.hippy.HippyEngine.ModuleLoadStatus; import com.tencent.mtt.hippy.bridge.HippyCallNativeParams; import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.TimeMonitor.MonitorGroup; -import com.tencent.mtt.hippy.utils.TimeMonitor.MonitorPoint; -import java.util.ArrayList; public class DefaultEngineMonitorAdapter implements HippyEngineMonitorAdapter { private static final String TAG = "DefaultEngineMonitorAdapter"; - protected void printGroupTime(@NonNull MonitorGroup monitorGroup) { - ArrayList monitorPoints = monitorGroup.getMonitorPoints(); - if (monitorPoints != null) { - for (MonitorPoint monitorPoint : monitorPoints) { - LogUtils.i(TAG, - monitorPoint.key + ": " + (monitorPoint.endTime - monitorPoint.startTime) - + "ms"); - } - } - LogUtils.i(TAG, "total time: " + monitorGroup.totalTime); - } - @Override - public void onEngineInitialized(EngineInitStatus statusCode, @NonNull MonitorGroup monitorGroup) { + public void onEngineInitialized(EngineInitStatus statusCode) { LogUtils.i(TAG, "engine initialization completed with result: " + statusCode); - printGroupTime(monitorGroup); } @Override - public void onLoadModuleCompleted(ModuleLoadStatus statusCode, @NonNull String componentName, - @NonNull MonitorGroup monitorGroup) { + public void onLoadModuleCompleted(ModuleLoadStatus statusCode, @NonNull String componentName) { LogUtils.i(TAG, componentName + " load module completed with result: " + statusCode); - printGroupTime(monitorGroup); } @Override - public void onLoadInstanceCompleted(@NonNull String componentName, - @NonNull MonitorGroup monitorGroup) { + public void onFirstPaintCompleted(@NonNull String componentName) { + LogUtils.i(TAG, + componentName + " first paint completed with first view added"); + } + + @Override + public void onFirstContentfulPaintCompleted(@NonNull String componentName) { LogUtils.i(TAG, - componentName + " load instance completed with first view added"); - printGroupTime(monitorGroup); + componentName + " first contentful paint completed last content view added"); } @Override diff --git a/framework/android/src/main/java/com/tencent/mtt/hippy/adapter/monitor/HippyEngineMonitorAdapter.java b/framework/android/src/main/java/com/tencent/mtt/hippy/adapter/monitor/HippyEngineMonitorAdapter.java index 331e04f93e1..66cb5328bbe 100644 --- a/framework/android/src/main/java/com/tencent/mtt/hippy/adapter/monitor/HippyEngineMonitorAdapter.java +++ b/framework/android/src/main/java/com/tencent/mtt/hippy/adapter/monitor/HippyEngineMonitorAdapter.java @@ -22,19 +22,18 @@ import com.tencent.mtt.hippy.HippyEngine.EngineInitStatus; import com.tencent.mtt.hippy.HippyEngine.ModuleLoadStatus; import com.tencent.mtt.hippy.bridge.HippyCallNativeParams; -import com.tencent.mtt.hippy.utils.TimeMonitor.MonitorGroup; public interface HippyEngineMonitorAdapter { - void onEngineInitialized(EngineInitStatus statusCode, @NonNull MonitorGroup monitorGroup); + void onEngineInitialized(EngineInitStatus statusCode); - void onLoadModuleCompleted(ModuleLoadStatus statusCode, @NonNull String componentName, - @NonNull MonitorGroup monitorGroup); + void onLoadModuleCompleted(ModuleLoadStatus statusCode, @NonNull String componentName); - void onLoadInstanceCompleted(@NonNull String componentName, @NonNull MonitorGroup monitorGroup); + void onFirstPaintCompleted(@NonNull String componentName); - boolean onInterceptCallNative(@NonNull String componentName, - @NonNull HippyCallNativeParams params); + void onFirstContentfulPaintCompleted(@NonNull String componentName); + + boolean onInterceptCallNative(@NonNull String componentName, @NonNull HippyCallNativeParams params); void onCallNativeFinished(@NonNull String componentName, @NonNull HippyCallNativeParams params); diff --git a/framework/android/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeImpl.java b/framework/android/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeImpl.java index 06795df5631..be142d2d3f6 100644 --- a/framework/android/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeImpl.java +++ b/framework/android/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeImpl.java @@ -26,8 +26,6 @@ import com.openhippy.connector.JsDriver.V8InitParams; import com.tencent.mtt.hippy.HippyEngineContext; import com.tencent.mtt.hippy.devsupport.DevSupportManager; -import com.tencent.mtt.hippy.utils.TimeMonitor; -import com.tencent.mtt.hippy.utils.TimeMonitor.MonitorGroupType; import com.tencent.mtt.hippy.utils.UIThreadUtils; import com.tencent.vfs.ResourceDataHolder; @@ -99,7 +97,6 @@ public void initJSBridge(String globalConfig, NativeCallback callback, final int } private void initJSEngine(int groupId, NativeCallback callback) { - mContext.getMonitor().startPoint(MonitorGroupType.ENGINE_INITIALIZE, TimeMonitor.MONITOR_POINT_INIT_JS_ENGINE); synchronized (HippyBridgeImpl.class) { try { String localCachePath = mContext.getGlobalConfigs().getContext().getCacheDir() diff --git a/framework/android/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeManagerImpl.java b/framework/android/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeManagerImpl.java index ebd3d732da2..b1b854b1829 100644 --- a/framework/android/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeManagerImpl.java +++ b/framework/android/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeManagerImpl.java @@ -49,7 +49,6 @@ import com.tencent.mtt.hippy.utils.DimensionsUtil; import com.tencent.mtt.hippy.utils.I18nUtil; import com.tencent.mtt.hippy.utils.TimeMonitor; -import com.tencent.mtt.hippy.utils.TimeMonitor.MonitorGroupType; import java.lang.ref.WeakReference; import org.json.JSONObject; @@ -225,6 +224,7 @@ public void Call(long result, Message message, String action, String reason) { @Override public boolean handleMessage(Message msg) { + final TimeMonitor timeMonitor = mContext.getMonitor(); try { switch (msg.what) { case MSG_CODE_INIT_BRIDGE: { @@ -253,9 +253,8 @@ public void Call(long result, Message message, String action, mThirdPartyAdapter.onRuntimeInit(runtimeId); } if (mCoreBundleLoader != null) { - final TimeMonitor timeMonitor = mContext.getMonitor(); - timeMonitor.startPoint(MonitorGroupType.ENGINE_INITIALIZE, - TimeMonitor.MONITOR_POINT_LOAD_COMMON_JS); + timeMonitor.addPoint(TimeMonitor.MONITOR_GROUP_INIT_ENGINE, + TimeMonitor.MONITOR_POINT_LOAD_VENDOR_JS); mCoreBundleLoader .load(mHippyBridge, new NativeCallback(mHandler) { @Override @@ -272,10 +271,8 @@ public void Call(long result, Message message, "load coreJsBundle failed, check your core jsBundle:" + reason); } - timeMonitor.startPoint( - MonitorGroupType.ENGINE_INITIALIZE, - TimeMonitor.MONITOR_POINT_NOTIFY_ENGINE_INITIALIZED); callback.callback((result == 0), exception); + timeMonitor.endGroup(TimeMonitor.MONITOR_GROUP_INIT_ENGINE); } }); } else { @@ -304,8 +301,7 @@ public void Call(long result, Message message, } final String bundleUniKey = loader.getBundleUniKey(); if (mLoadedBundleInfo != null && !TextUtils.isEmpty(bundleUniKey) - && mLoadedBundleInfo - .contains(bundleUniKey)) { + && mLoadedBundleInfo.contains(bundleUniKey)) { mContext.onLoadModuleCompleted(ModuleLoadStatus.STATUS_REPEAT_LOAD, "repeat load module. loader.getBundleUniKey=" + bundleUniKey); return true; @@ -332,6 +328,9 @@ public void Call(long result, Message message, String action, "load module error. loader.load failed. check the file!!"); } } + timeMonitor.endGroup(TimeMonitor.MONITOR_GROUP_RUN_BUNDLE); + timeMonitor.beginGroup(TimeMonitor.MONITOR_GROUP_PAINT); + timeMonitor.addPoint(TimeMonitor.MONITOR_GROUP_PAINT, TimeMonitor.MONITOR_POINT_FIRST_PAINT); } }); } else { @@ -371,8 +370,9 @@ public void initBridge(Callback callback) { @Override public void runBundle(int id, HippyBundleLoader loader) { if (mHandler != null) { - mContext.getMonitor().startPoint(MonitorGroupType.RUN_JS_BUNDLE, - TimeMonitor.MONITOR_POINT_LOAD_BUSINESS_JS); + mContext.getMonitor().beginGroup(TimeMonitor.MONITOR_GROUP_RUN_BUNDLE); + mContext.getMonitor().addPoint(TimeMonitor.MONITOR_GROUP_RUN_BUNDLE, + TimeMonitor.MONITOR_POINT_LOAD_MAIN_JS); Message message = mHandler.obtainMessage(MSG_CODE_RUN_BUNDLE, 0, id, loader); mHandler.sendMessage(message); } @@ -381,8 +381,8 @@ public void runBundle(int id, HippyBundleLoader loader) { @Override public void loadInstance(String name, int id, HippyMap params) { if (mHandler != null) { - mContext.getMonitor().startPoint(MonitorGroupType.LOAD_INSTANCE, - TimeMonitor.MONITOR_POINT_LOAD_INSTANCE); + mContext.getMonitor().beginGroup(TimeMonitor.MONITOR_GROUP_PAINT); + mContext.getMonitor().addPoint(TimeMonitor.MONITOR_GROUP_PAINT, TimeMonitor.MONITOR_POINT_FIRST_PAINT); HippyMap map = new HippyMap(); map.pushString("name", name); map.pushInt("id", id); diff --git a/modules/android/hippy_support/src/main/java/com/tencent/mtt/hippy/utils/TimeMonitor.java b/modules/android/hippy_support/src/main/java/com/tencent/mtt/hippy/utils/TimeMonitor.java index ee42803fa07..ab0a338b10a 100644 --- a/modules/android/hippy_support/src/main/java/com/tencent/mtt/hippy/utils/TimeMonitor.java +++ b/modules/android/hippy_support/src/main/java/com/tencent/mtt/hippy/utils/TimeMonitor.java @@ -24,83 +24,101 @@ public class TimeMonitor { - public enum MonitorGroupType { - ENGINE_INITIALIZE, - RUN_JS_BUNDLE, - LOAD_INSTANCE, - VFS_RESOURCE_LOAD - } + private static final String TAG = "HippyTimeMonitor"; + + public static final String MONITOR_GROUP_INIT_ENGINE = "initEngine"; + public static final String MONITOR_GROUP_RUN_BUNDLE = "runBundle"; + public static final String MONITOR_GROUP_PAINT = "paint"; public static final String MONITOR_POINT_INIT_NATIVE_ENGINE = "initNativeEngine"; - public static final String MONITOR_POINT_INIT_JS_ENGINE = "initJSEngine"; - public static final String MONITOR_POINT_LOAD_COMMON_JS = "loadCommonJs"; - public static final String MONITOR_POINT_NOTIFY_ENGINE_INITIALIZED = "notifyEngineInitialized"; - public static final String MONITOR_POINT_LOAD_BUSINESS_JS = "loadBusinessJs"; - public static final String MONITOR_POINT_LOAD_INSTANCE = "loadInstance"; - public static final String MONITOR_POINT_FIRST_FRAME = "firstFrame"; + public static final String MONITOR_POINT_LOAD_VENDOR_JS = "loadVendorJs"; + public static final String MONITOR_POINT_LOAD_MAIN_JS = "loadMainJs"; + public static final String MONITOR_POINT_FIRST_PAINT = "firstPaint"; + public static final String MONITOR_POINT_FIRST_CONTENTFUL_PAINT = "firstContentfulPaint"; @Nullable - HashMap mMonitorGroups; + HashMap mMonitorGroups; - public synchronized void startPoint(@NonNull MonitorGroupType groupType, - @NonNull String point) { + public synchronized void beginGroup(@NonNull String groupName) { if (mMonitorGroups == null) { mMonitorGroups = new HashMap<>(); } - MonitorGroup monitorGroup = mMonitorGroups.get(groupType); + MonitorGroup monitorGroup = mMonitorGroups.get(groupName); if (monitorGroup == null) { - monitorGroup = new MonitorGroup(groupType); - mMonitorGroups.put(groupType, monitorGroup); + monitorGroup = new MonitorGroup(groupName); + mMonitorGroups.put(groupName, monitorGroup); + } else { + monitorGroup.reset(); } - monitorGroup.startPoint(point); } - @Nullable - public synchronized MonitorGroup endGroup(@NonNull MonitorGroupType groupType) { + public synchronized void addPoint(@NonNull String groupName, @NonNull String point) { if (mMonitorGroups == null) { - return null; + return; + } + MonitorGroup monitorGroup = mMonitorGroups.get(groupName); + if (monitorGroup != null) { + monitorGroup.addPoint(point); } - MonitorGroup monitorGroup = mMonitorGroups.get(groupType); + } + + public synchronized void endGroup(@NonNull String groupName) { + if (mMonitorGroups == null) { + return; + } + MonitorGroup monitorGroup = mMonitorGroups.get(groupName); if (monitorGroup != null) { monitorGroup.end(); } - return monitorGroup; } - @Nullable - public synchronized MonitorGroup getMonitorGroup (@NonNull MonitorGroupType groupType) { + public synchronized void printGroup(@NonNull String groupName) { if (mMonitorGroups == null) { - return null; + return; + } + MonitorGroup monitorGroup = mMonitorGroups.get(groupName); + if (monitorGroup != null) { + monitorGroup.print(); } - return (mMonitorGroups == null) ? null : mMonitorGroups.get(groupType); } - public static class MonitorGroup { + private static class MonitorGroup { - public final MonitorGroupType type; + public final String name; public long beginTime = -1; public long totalTime = -1; - public boolean isActive; + public boolean isActive = true; @Nullable private ArrayList mMonitorPoints; @Nullable private MonitorPoint mLastPoint; - public MonitorGroup(@NonNull MonitorGroupType type) { - this.type = type; - isActive = true; + public MonitorGroup(@NonNull String name) { + this.name = name; } @Nullable private MonitorPoint checkMonitorPoint(@NonNull String pointKey) { - for (MonitorPoint monitorPoint : mMonitorPoints) { - if (monitorPoint.key.equals(pointKey)) { - return monitorPoint; + if (mMonitorPoints != null) { + for (MonitorPoint monitorPoint : mMonitorPoints) { + if (monitorPoint.key.equals(pointKey)) { + return monitorPoint; + } } } return null; } - void startPoint(@NonNull String pointKey) { + void reset() { + beginTime = -1; + totalTime = -1; + isActive = true; + mLastPoint = null; + if (mMonitorPoints != null) { + mMonitorPoints.clear(); + } + } + + void addPoint(@NonNull String pointKey) { if (!isActive) { return; } @@ -108,10 +126,11 @@ void startPoint(@NonNull String pointKey) { mMonitorPoints = new ArrayList<>(); } MonitorPoint monitorPoint = checkMonitorPoint(pointKey); - if (monitorPoint == null) { - monitorPoint = new MonitorPoint(pointKey); - mMonitorPoints.add(monitorPoint); + if (monitorPoint != null) { + return; } + monitorPoint = new MonitorPoint(pointKey); + mMonitorPoints.add(monitorPoint); long currentTime = System.currentTimeMillis(); monitorPoint.startTime = currentTime; if (mLastPoint != null) { @@ -132,6 +151,18 @@ void end() { if (beginTime != -1) { totalTime = (int) (System.currentTimeMillis() - beginTime); } + print(); + } + } + + void print() { + if (mMonitorPoints != null) { + LogUtils.i(TAG, "group " + name + ", totalTime " + totalTime + "ms"); + for (MonitorPoint monitorPoint : mMonitorPoints) { + LogUtils.i(TAG, + monitorPoint.key + ": " + (monitorPoint.endTime - monitorPoint.startTime) + + "ms"); + } } } diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/HippyRootView.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/HippyRootView.java index 172900ead5a..efa30b06893 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/HippyRootView.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/HippyRootView.java @@ -63,7 +63,7 @@ public void onViewAdded(View child) { firstViewAdded = true; NativeRender nativeRenderer = NativeRendererManager.getNativeRenderer(getContext()); if (nativeRenderer != null) { - nativeRenderer.onFirstViewAdded(); + nativeRenderer.onFirstPaint(); } } } diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/FrameworkProxy.java b/renderer/native/android/src/main/java/com/tencent/renderer/FrameworkProxy.java index bb931f460ad..3479923a9bd 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/FrameworkProxy.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/FrameworkProxy.java @@ -49,7 +49,9 @@ public interface FrameworkProxy { int getEngineId(); - void onFirstViewAdded(); + void onFirstPaint(); + + void onFirstContentfulPaint(); void handleNativeException(Exception exception); diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRender.java b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRender.java index 1969583193d..91c2e953aca 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRender.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRender.java @@ -23,7 +23,6 @@ import androidx.annotation.Nullable; import com.tencent.mtt.hippy.HippyInstanceLifecycleEventListener; -import com.tencent.mtt.hippy.common.LogAdapter; import com.tencent.mtt.hippy.uimanager.RenderManager; import com.tencent.renderer.component.image.ImageDecoderAdapter; @@ -92,7 +91,9 @@ public interface NativeRender extends RenderExceptionHandler, RenderLogHandler { VirtualNode createVirtualNode(int rootId, int id, int pid, int index, @NonNull String className, @Nullable Map props); - void onFirstViewAdded(); + void onFirstPaint(); + + void onFirstContentfulPaint(); void onSizeChanged(int rootId, int width, int height, int oldWidth, int oldHeight); diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java index d130efcfefd..3aefd909f77 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java @@ -108,6 +108,8 @@ public class NativeRenderer extends Renderer implements NativeRender, NativeRend private static final String EVENT_PREFIX = "on"; private static final String SNAPSHOT_CREATE_NODE = "createNode"; private static final String SNAPSHOT_UPDATE_LAYOUT = "updateLayout"; + private static final String PAINT_TYPE_KEY = "paintType"; + private static final String FCP_VALUE = "fcp"; /** * The max capacity of UI task queue */ @@ -115,6 +117,7 @@ public class NativeRenderer extends Renderer implements NativeRender, NativeRend private static final int ROOT_VIEW_ID_INCREMENT = 10; private static final int INVALID_NODE_ID = -1; private static final AtomicInteger sRootIdCounter = new AtomicInteger(0); + private FCPBatchState mFcpBatchState = FCPBatchState.WATCHING; @Nullable private FrameworkProxy mFrameworkProxy; @Nullable @@ -132,6 +135,12 @@ public class NativeRenderer extends Renderer implements NativeRender, NativeRend @Nullable private ImageLoaderAdapter mImageLoader; + public enum FCPBatchState { + WATCHING, + DETECTED, + MARKED, + } + public NativeRenderer() { mRenderProvider = new NativeRenderProvider(this); // Should restrictions the capacity of ui task queue, to avoid js make huge amount of @@ -345,9 +354,16 @@ public View getRootView(@NonNull View view) { } @Override - public void onFirstViewAdded() { + public void onFirstPaint() { + if (mFrameworkProxy != null) { + mFrameworkProxy.onFirstPaint(); + } + } + + @Override + public void onFirstContentfulPaint() { if (mFrameworkProxy != null) { - mFrameworkProxy.onFirstViewAdded(); + mFrameworkProxy.onFirstContentfulPaint(); } } @@ -476,6 +492,14 @@ private UITaskExecutor getMassTaskExecutor(@NonNull final List t }; } + private void updateFcpStateIfNeeded(int rootId, @Nullable Map props) { + if (mFcpBatchState == FCPBatchState.WATCHING && props != null && rootId != SCREEN_SNAPSHOT_ROOT_ID) { + if (MapUtils.getStringValue(props, PAINT_TYPE_KEY, "").equalsIgnoreCase(FCP_VALUE)) { + mFcpBatchState = FCPBatchState.DETECTED; + } + } + } + @SuppressWarnings({"unchecked"}) @Override public void createNode(final int rootId, @NonNull List nodeList) @@ -504,6 +528,7 @@ public void createNode(final int rootId, @NonNull List nodeList) + ", index " + nodeIndex + ", name " + className + "\n props " + props + "\n "); } + updateFcpStateIfNeeded(rootId, props); mVirtualNodeManager.createNode(rootId, nodeId, nodePid, nodeIndex, className, props); // If multiple level are nested, the parent is outermost text node. VirtualNode parent = mVirtualNodeManager.checkVirtualParent(rootId, nodeId); @@ -571,6 +596,7 @@ public void updateNode(final int rootId, @NonNull List nodeList) "updateNode: id " + nodeId + ", diff " + diffProps + ", delete " + delProps + "\n "); } + updateFcpStateIfNeeded(rootId, diffProps); mVirtualNodeManager.updateNode(rootId, nodeId, diffProps, delProps); // If multiple level are nested, the parent is outermost text node. VirtualNode parent = mVirtualNodeManager.checkVirtualParent(rootId, nodeId); @@ -783,7 +809,16 @@ public void endBatch(final int rootId) throws NativeRenderException { if (rootId == SCREEN_SNAPSHOT_ROOT_ID) { mRenderManager.batch(rootId); } else { - addUITask(() -> mRenderManager.batch(rootId)); + final boolean isFcp = (mFcpBatchState == FCPBatchState.DETECTED); + addUITask(() -> { + mRenderManager.batch(rootId); + if (isFcp) { + onFirstContentfulPaint(); + } + }); + if (isFcp) { + mFcpBatchState = FCPBatchState.MARKED; + } executeUITask(); } }