diff --git a/driver/js/src/scope.cc b/driver/js/src/scope.cc index 5b5ef8a825f..56a97e40e76 100644 --- a/driver/js/src/scope.cc +++ b/driver/js/src/scope.cc @@ -527,7 +527,7 @@ void Scope::LoadInstance(const std::shared_ptr& value) { auto cb = [WEAK_THIS, weak_context, value]() mutable { #endif DEFINE_AND_CHECK_SELF(Scope) - // perfromance start time + // perfromance - RunApplication start time (end at DomStart) auto entry = self->GetPerformance()->PerformanceNavigation(kPerfNavigationHippyInit); entry->SetHippyRunApplicationStart(footstone::TimePoint::SystemNow()); @@ -561,9 +561,6 @@ void Scope::LoadInstance(const std::shared_ptr& value) { context->ThrowException("Application entry not found"); } } - - // perfromance end time - entry->SetHippyRunApplicationEnd(footstone::TimePoint::SystemNow()); }; auto runner = GetTaskRunner(); if (footstone::Worker::IsTaskRunning() && runner == footstone::runner::TaskRunner::GetCurrentTaskRunner()) { 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 e6b06fca8d3..3995a6d6781 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 @@ -214,6 +214,7 @@ void OnFirstPaintEnd(JNIEnv* j_env, jobject j_object, jint j_scope_id, jlong tim return; } auto entry = scope->GetPerformance()->PerformanceNavigation("hippyInit"); + entry->SetHippyRunApplicationEnd(dom_manager->GetDomStartTimePoint()); entry->SetHippyDomStart(dom_manager->GetDomStartTimePoint()); entry->SetHippyDomEnd(dom_manager->GetDomEndTimePoint()); entry->SetHippyFirstFrameStart(dom_manager->GetDomEndTimePoint()); diff --git a/framework/ios/base/bridge/HippyBridge+PerformanceAPI.mm b/framework/ios/base/bridge/HippyBridge+PerformanceAPI.mm index 43ab28ee850..e60b3adc90b 100644 --- a/framework/ios/base/bridge/HippyBridge+PerformanceAPI.mm +++ b/framework/ios/base/bridge/HippyBridge+PerformanceAPI.mm @@ -22,6 +22,7 @@ #import "HippyBridge+PerformanceAPI.h" #import "HippyJSExecutor.h" +#import "HippyLog.h" #import "driver/scope.h" @implementation HippyBridge (PerformanceAPI) @@ -38,10 +39,20 @@ - (void)updatePerfRecordsOnRootContentDidAppear { if (!entry) { return; } + entry->SetHippyRunApplicationEnd(domManager->GetDomStartTimePoint()); entry->SetHippyDomStart(domManager->GetDomStartTimePoint()); entry->SetHippyDomEnd(domManager->GetDomEndTimePoint()); entry->SetHippyFirstFrameStart(domManager->GetDomEndTimePoint()); entry->SetHippyFirstFrameEnd(footstone::TimePoint::SystemNow()); + +#if HIPPY_DEBUG + int64_t totalFPTime = (entry->GetHippyFirstFrameEnd() - entry->GetHippyNativeInitStart()).ToMilliseconds(); + auto nativeInit = (entry->GetHippyNativeInitEnd() - entry->GetHippyNativeInitStart()).ToMilliseconds(); + auto runApplication = (entry->GetHippyRunApplicationEnd() - entry->GetHippyRunApplicationStart()).ToMilliseconds(); + auto domCreate = (entry->GetHippyDomEnd() - entry->GetHippyDomStart()).ToMilliseconds(); + auto firstFrame = (entry->GetHippyFirstFrameEnd() - entry->GetHippyFirstFrameStart()).ToMilliseconds(); + HippyLogTrace(@"Hippy FP=%lld, detail: %lld, %lld, %lld, %lld", totalFPTime, nativeInit, runApplication, domCreate, firstFrame); +#endif /* HIPPY_DEBUG */ } } diff --git a/framework/ios/base/bridge/HippyBridge+Private.h b/framework/ios/base/bridge/HippyBridge+Private.h index faca1cdc9f4..7f6ef573704 100644 --- a/framework/ios/base/bridge/HippyBridge+Private.h +++ b/framework/ios/base/bridge/HippyBridge+Private.h @@ -24,6 +24,7 @@ #define HippyBridge_Private_h #import "HippyBridge.h" +#import "footstone/time_point.h" #include class VFSUriLoader; @@ -46,6 +47,9 @@ class RenderManager; /// URI Loader @property (nonatomic, assign) std::weak_ptr vfsUriLoader; +/// Start time of hippyBridge, for performance api. +@property (nonatomic, assign) footstone::TimePoint startTime; + @end diff --git a/framework/ios/base/bridge/HippyBridge.mm b/framework/ios/base/bridge/HippyBridge.mm index 3975c2cd3fe..26e02abe01f 100644 --- a/framework/ios/base/bridge/HippyBridge.mm +++ b/framework/ios/base/bridge/HippyBridge.mm @@ -52,27 +52,24 @@ #import "TypeConverter.h" #import "VFSUriLoader.h" #import "HippyBase64DataHandler.h" - -#include -#include -#include +#import "NativeRenderManager.h" +#import "HippyRootView.h" +#import "UIView+Hippy.h" +#import "UIView+MountEvent.h" #include "dom/animation/animation_manager.h" #include "dom/dom_manager.h" #include "dom/scene.h" #include "dom/render_manager.h" #include "driver/scope.h" -#include "driver/performance/performance.h" #include "footstone/worker_manager.h" #include "vfs/uri_loader.h" #include "VFSUriHandler.h" #include "footstone/logging.h" -#import "NativeRenderManager.h" -#import "HippyRootView.h" -#import "UIView+Hippy.h" -#import "UIView+MountEvent.h" - +#include +#include +#include #ifdef ENABLE_INSPECTOR #include "devtools/vfs/devtools_handler.h" @@ -155,8 +152,6 @@ @interface HippyBridge() { NSMutableArray *_bundleURLs; NSURL *_sandboxDirectory; - footstone::TimePoint _startTime; - std::shared_ptr _uriLoader; std::shared_ptr _rootNode; @@ -187,6 +182,7 @@ @implementation HippyBridge @synthesize renderManager = _renderManager; @synthesize imageLoader = _imageLoader; @synthesize imageProviders = _imageProviders; +@synthesize startTime = _startTime; dispatch_queue_t HippyJSThread; @@ -439,10 +435,6 @@ - (void)setUp { HippyBridge *strongSelf = weakSelf; if (strongSelf) { dispatch_semaphore_signal(strongSelf.moduleSemaphore); - footstone::TimePoint endTime = footstone::TimePoint::SystemNow(); - auto enty = strongSelf.javaScriptExecutor.pScope->GetPerformance()->PerformanceNavigation(hippy::kPerfNavigationHippyInit); - enty->SetHippyNativeInitStart(strongSelf->_startTime); - enty->SetHippyNativeInitEnd(endTime); } }]; diff --git a/framework/ios/base/executors/HippyJSExecutor.h b/framework/ios/base/executors/HippyJSExecutor.h index 83ea6c17054..9f049f907a0 100644 --- a/framework/ios/base/executors/HippyJSExecutor.h +++ b/framework/ios/base/executors/HippyJSExecutor.h @@ -55,49 +55,59 @@ class UriLoader; typedef void (^HippyContextCreatedBlock)(id); -/** - * Default name for the JS thread - */ -HIPPY_EXTERN NSString *const HippyJSCThreadName; /** * Uses a JavaScriptCore context as the execution engine. */ @interface HippyJSExecutor : NSObject -@property (nonatomic, strong) HippyBridge *bridge; +/// HippyBridge instance +@property (nonatomic, weak) HippyBridge *bridge; /** * Whether the executor has been invalidated */ @property (nonatomic, readonly, getter=isValid) BOOL valid; +/// EngineKey @property (nonatomic, copy) NSString *enginekey; -/* - *hippy-core js engine - */ + +/// hippy scope @property (atomic, assign) std::shared_ptr pScope; +/// context created block @property(nonatomic, copy) HippyContextCreatedBlock contextCreatedBlock; +/// Init method +/// - Parameters: +/// - engineKey: NSString +/// - bridge: HippyBridge instance - (instancetype)initWithEngineKey:(NSString *)engineKey bridge:(HippyBridge *)bridge; -/** - * Used to set up the executor after the bridge has been fully initialized. - * Do any expensive setup in this method instead of `-init`. - */ +/// Used to set up the executor after bridge has been fully initialized. - (void)setup; +/// Set sandbox directory for Hippy +/// - Parameter directory: NSString - (void)setSandboxDirectory:(NSString *)directory; +/// Set context name +/// - Parameter contextName: NSString - (void)setContextName:(NSString *)contextName; +/// Set whether js engine is inspectable +/// - Parameter inspectable: BOOL - (void)setInspecable:(BOOL)inspectable; +/// Set Uri loader +/// - Parameter uriLoader: vfs::UriLoader - (void)setUriLoader:(std::weak_ptr)uriLoader; +/// Get turbo object +/// - Parameter name: NSString - (std::shared_ptr)JSTurboObjectWithName:(NSString *)name; +// TODO: 疑似已废弃 /** * Executes BatchedBridge.flushedQueue on JS thread and calls the given callback * with JSValue, containing the next queue, and JSContext. @@ -109,7 +119,10 @@ HIPPY_EXTERN NSString *const HippyJSCThreadName; * method name and optional additional arguments on the JS thread and calls the * given callback with JSValue, containing the next queue, and JSContext. */ -- (void)callFunctionOnModule:(NSString *)module method:(NSString *)method arguments:(NSArray *)args callback:(HippyJavaScriptCallback)onComplete; +- (void)callFunctionOnModule:(NSString *)moduleName + method:(NSString *)method + arguments:(NSArray *)args + callback:(HippyJavaScriptCallback)onComplete; /** * Executes BatchedBridge.invokeCallbackAndReturnFlushedQueue with the cbID, diff --git a/framework/ios/base/executors/HippyJSExecutor.mm b/framework/ios/base/executors/HippyJSExecutor.mm index 6351b1bea37..c01e4fad905 100644 --- a/framework/ios/base/executors/HippyJSExecutor.mm +++ b/framework/ios/base/executors/HippyJSExecutor.mm @@ -20,7 +20,7 @@ * limitations under the License. */ -#import +#import "HippyJSExecutor.h" #import "VFSUriHandler.h" #import "HippyAssert.h" #import "HippyBundleURLProvider.h" @@ -29,7 +29,6 @@ #import "HippyDevInfo.h" #import "HippyDevMenu.h" #import "HippyJSEnginesMapper.h" -#import "HippyJSExecutor.h" #import "HippyOCTurboModule+Inner.h" #import "HippyRedBox.h" #import "HippyUtils.h" @@ -39,6 +38,7 @@ #import "HippyFootstoneUtils.h" #import "NSObject+CtxValue.h" #import "TypeConverter.h" +#import "HippyBridge+Private.h" #include #include @@ -63,10 +63,6 @@ #include "devtools/devtools_data_source.h" #endif -NSString *const HippyJSCThreadName = @"com.tencent.hippy.JavaScript"; - -constexpr char kGlobalKey[] = "global"; -constexpr char kHippyKey[] = "Hippy"; using string_view = footstone::stringview::string_view; using StringViewUtils = footstone::stringview::StringViewUtils; @@ -75,10 +71,17 @@ using SharedCtxValuePtr = std::shared_ptr; using WeakCtxValuePtr = std::weak_ptr; + +constexpr char kGlobalKey[] = "global"; +constexpr char kHippyKey[] = "Hippy"; +static NSString * const kHippyNativeGlobalKey = @"__HIPPYNATIVEGLOBAL__"; + + + @interface HippyJSExecutor () { // Set at setUp time: id _contextWrapper; - __weak HippyBridge *_bridge; + #ifdef JS_JSC BOOL _isInspectable; #endif //JS_JSC @@ -91,26 +94,20 @@ @interface HippyJSExecutor () { @end -@implementation HippyJSExecutor - -- (void)setBridge:(HippyBridge *)bridge { - _bridge = bridge; -} -- (HippyBridge *)bridge { - return _bridge; -} +@implementation HippyJSExecutor - (void)setup { auto engine = [[HippyJSEnginesMapper defaultInstance] createJSEngineResourceForKey:self.enginekey]; const char *pName = [self.enginekey UTF8String] ?: ""; - footstone::TimePoint startPoint = footstone::TimePoint::SystemNow(); auto scope = engine->GetEngine()->CreateScope(pName); + dispatch_semaphore_t scopeSemaphore = dispatch_semaphore_create(0); __weak HippyJSExecutor *weakSelf = self; + footstone::TimePoint startPoint = footstone::TimePoint::SystemNow(); engine->GetEngine()->GetJsTaskRunner()->PostTask([weakSelf, scopeSemaphore, startPoint](){ @autoreleasepool { - HippyJSExecutor *strongSelf = weakSelf; + __strong __typeof(weakSelf)strongSelf = weakSelf; if (!strongSelf) { return; } @@ -118,17 +115,26 @@ - (void)setup { if (!bridge) { return; } + dispatch_semaphore_wait(scopeSemaphore, DISPATCH_TIME_FOREVER); auto scope = strongSelf->_pScope; scope->CreateContext(); auto context = scope->GetContext(); auto global_object = context->GetGlobalObject(); + + // add `global` property to global object auto user_global_object_key = context->CreateString(kGlobalKey); context->SetProperty(global_object, user_global_object_key, global_object); + + // add `Hippy` property to global object auto hippy_key = context->CreateString(kHippyKey); context->SetProperty(global_object, hippy_key, context->CreateObject()); + + // Context Wrapper id contextWrapper = CreateContextWrapper(context); - contextWrapper.excpetionHandler = ^(id _Nonnull wrapper, NSString * _Nonnull message, NSArray * _Nonnull stackFrames) { + contextWrapper.excpetionHandler = ^(id _Nonnull wrapper, + NSString * _Nonnull message, + NSArray * _Nonnull stackFrames) { HippyJSExecutor *strongSelf = weakSelf; if (!strongSelf) { return; @@ -146,22 +152,25 @@ - (void)setup { HippyBridgeFatal(error, bridge); }; strongSelf->_contextWrapper = contextWrapper; + + // inject device info information NSMutableDictionary *deviceInfo = [NSMutableDictionary dictionaryWithDictionary:[bridge deviceInfo]]; NSString *deviceName = [[UIDevice currentDevice] name]; NSString *clientId = HippyMD5Hash([NSString stringWithFormat:@"%@%p", deviceName, strongSelf]); NSDictionary *debugInfo = @{@"Debug" : @{@"debugClientId" : clientId}}; [deviceInfo addEntriesFromDictionary:debugInfo]; - NSError *JSONSerializationError = nil; - NSData *data = [NSJSONSerialization dataWithJSONObject:deviceInfo options:0 error:&JSONSerializationError]; - if (JSONSerializationError) { - NSString *errorString = - [NSString stringWithFormat:@"device parse error:%@, deviceInfo:%@", [JSONSerializationError localizedFailureReason], deviceInfo]; + NSError *serializationError; + NSString *deviceInfoStr = HippyJSONStringify(deviceInfo, &serializationError); + if (serializationError) { + NSString *errorString = [NSString stringWithFormat:@"device parse error:%@, deviceInfo:%@", + [serializationError localizedFailureReason], deviceInfo]; NSError *error = HippyErrorWithMessageAndModuleName(errorString, bridge.moduleName); HippyBridgeFatal(error, bridge); } - NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - [contextWrapper createGlobalObject:@"__HIPPYNATIVEGLOBAL__" withJsonValue:string]; + [contextWrapper createGlobalObject:kHippyNativeGlobalKey withJsonValue:deviceInfoStr]; + + // regist `nativeRequireModuleConfig` function [contextWrapper registerFunction:@"nativeRequireModuleConfig" implementation:^id _Nullable(NSArray * _Nonnull arguments) { NSString *moduleName = [arguments firstObject]; if (moduleName) { @@ -178,6 +187,8 @@ - (void)setup { } return nil; }]; + + // regist `nativeFlushQueueImmediate` function [contextWrapper registerFunction:@"nativeFlushQueueImmediate" implementation:^id _Nullable(NSArray * _Nonnull arguments) { NSArray *calls = [arguments firstObject]; HippyJSExecutor *strongSelf = weakSelf; @@ -191,6 +202,7 @@ - (void)setup { [bridge handleBuffer:calls batchEnded:NO]; return nil; }]; + auto turbo_wrapper = std::make_unique([](hippy::CallbackInfo& info, void* data) { @autoreleasepool { //todo @@ -209,12 +221,24 @@ - (void)setup { auto turbo_function = context->CreateFunction(turbo_wrapper); scope->SaveFunctionWrapper(std::move(turbo_wrapper)); context->SetProperty(global_object, context->CreateString("getTurboModule"), turbo_function); + + // call finish block if (strongSelf.contextCreatedBlock) { strongSelf.contextCreatedBlock(strongSelf->_contextWrapper); } scope->SyncInitialize(); - // execute pending blocks + // performance record + footstone::TimePoint endTime = footstone::TimePoint::SystemNow(); + auto entry = scope->GetPerformance()->PerformanceNavigation(hippy::kPerfNavigationHippyInit); + if (entry) { + entry->SetHippyJsEngineInitStart(startPoint); + entry->SetHippyJsEngineInitEnd(endTime); + entry->SetHippyNativeInitStart(strongSelf.bridge.startTime); + entry->SetHippyNativeInitEnd(endTime); + } + + // the last, execute pending blocks NSArray *pendingCalls; @synchronized (strongSelf) { strongSelf.ready = YES; @@ -224,15 +248,11 @@ - (void)setup { [pendingCalls enumerateObjectsUsingBlock:^(dispatch_block_t _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { [strongSelf executeBlockOnJavaScriptQueue:obj]; }]; - - // performance record - auto entry = scope->GetPerformance()->PerformanceNavigation(hippy::kPerfNavigationHippyInit); - entry->SetHippyJsEngineInitStart(startPoint); - entry->SetHippyJsEngineInitEnd(footstone::TimePoint::SystemNow()); } }); self.pScope = scope; dispatch_semaphore_signal(scopeSemaphore); + #ifdef ENABLE_INSPECTOR HippyBridge *bridge = self.bridge; if (bridge && bridge.debugMode) { @@ -261,6 +281,46 @@ - (instancetype)initWithEngineKey:(NSString *)engineKey bridge:(HippyBridge *)br return self; } +- (void)dealloc { + HippyLogInfo(@"[Hippy_OC_Log][Life_Circle],HippyJSCExecutor dealloc %p", self); + [self invalidate]; +} + +- (void)invalidate { + if (!self.isValid) { + return; + } +#ifdef ENABLE_INSPECTOR + auto devtools_data_source = self.pScope->GetDevtoolsDataSource(); + if (devtools_data_source) { + bool reload = self.bridge.invalidateReason == HippyInvalidateReasonReload ? true : false; + devtools_data_source->Destroy(reload); + } +#endif + HippyLogInfo(@"[Hippy_OC_Log][Life_Circle],HippyJSCExecutor invalide %p", self); + _valid = NO; +#ifdef JS_JSC + auto scope = self.pScope; + if (scope) { + auto jsc_context = std::static_pointer_cast(scope->GetContext()); + static CFStringRef delName = CFSTR("HippyJSContext(delete)"); + jsc_context->SetName(delName); + } +#endif //JS_JSC + self.pScope->WillExit(); + self.pScope = nullptr; + NSString *enginekey = self.enginekey; + if (!enginekey) { + return; + } + dispatch_async(dispatch_get_main_queue(), ^{ + [[HippyJSEnginesMapper defaultInstance] removeEngineResourceForKey:enginekey]; + }); +} + + +#pragma mark - + - (void)setUriLoader:(std::weak_ptr)uriLoader { if (self.pScope->GetUriLoader().lock() != uriLoader.lock()) { self.pScope->SetUriLoader(uriLoader); @@ -342,38 +402,6 @@ - (SharedCtxValuePtr)JSTurboObjectWithName:(NSString *)name { return obj; } -- (void)invalidate { - if (!self.isValid) { - return; - } -#ifdef ENABLE_INSPECTOR - auto devtools_data_source = self.pScope->GetDevtoolsDataSource(); - if (devtools_data_source) { - bool reload = self.bridge.invalidateReason == HippyInvalidateReasonReload ? true : false; - devtools_data_source->Destroy(reload); - } -#endif - HippyLogInfo(@"[Hippy_OC_Log][Life_Circle],HippyJSCExecutor invalide %p", self); - _valid = NO; -#ifdef JS_JSC - auto scope = self.pScope; - if (scope) { - auto jsc_context = std::static_pointer_cast(scope->GetContext()); - static CFStringRef delName = CFSTR("HippyJSContext(delete)"); - jsc_context->SetName(delName); - } -#endif //JS_JSC - self.pScope->WillExit(); - self.pScope = nullptr; - NSString *enginekey = self.enginekey; - if (!enginekey) { - return; - } - dispatch_async(dispatch_get_main_queue(), ^{ - [[HippyJSEnginesMapper defaultInstance] removeEngineResourceForKey:enginekey]; - }); -} - - (void)setContextName:(NSString *)contextName { #ifdef JS_JSC if (!contextName) { @@ -424,11 +452,6 @@ - (void)setInspecable:(BOOL)inspectable { #endif //JS_JSC } -- (void)dealloc { - HippyLogInfo(@"[Hippy_OC_Log][Life_Circle],HippyJSCExecutor dealloc %p", self); - [self invalidate]; -} - - (void)updateNativeInfoToHippyGlobalObject:(NSDictionary *)updatedInfoDict { if (updatedInfoDict.count <= 0){ return; @@ -443,8 +466,8 @@ - (void)updateNativeInfoToHippyGlobalObject:(NSDictionary *)updatedInfoDict { }]; } --(void)addInfoToGlobalObject:(NSDictionary*)addInfoDict{ - string_view str("__HIPPYNATIVEGLOBAL__"); +- (void)addInfoToGlobalObject:(NSDictionary*)addInfoDict{ + string_view str(kHippyNativeGlobalKey.UTF8String); auto context = self.pScope->GetContext(); auto global_object = context->GetGlobalObject(); auto hippy_native_object_key = context->CreateString(str);