Skip to content

Commit 5ef6e8d

Browse files
committed
This commits adds profiling in several places, showing some instances where the runtime block the JavaScript thread
Log all c++ frames, log some key methods in Java Add package.json "profiling": "timeline" option to enable the logging of the manual instrumentation profiling
1 parent 1a02d15 commit 5ef6e8d

File tree

16 files changed

+721
-328
lines changed

16 files changed

+721
-328
lines changed

build-artifacts/project-template-gradle/src/main/java/com/tns/NativeScriptApplication.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@ public NativeScriptApplication() {
1111
}
1212

1313
public void onCreate() {
14-
super.onCreate();
15-
com.tns.Runtime runtime = RuntimeHelper.initRuntime(this);
16-
if (runtime !=null) {
17-
runtime.run();
14+
ManualInstrumentation.Frame frame = ManualInstrumentation.start("NaitveScriptApplication.onCreate");
15+
try {
16+
super.onCreate();
17+
com.tns.Runtime runtime = RuntimeHelper.initRuntime(this);
18+
if (runtime != null) {
19+
runtime.run();
20+
}
21+
} finally {
22+
frame.close();
1823
}
1924
}
2025

build-artifacts/project-template-gradle/src/main/java/com/tns/RuntimeHelper.java

Lines changed: 142 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -53,157 +53,180 @@ public static Runtime initRuntime(Application app) {
5353
return Runtime.getCurrentRuntime();
5454
}
5555

56-
System.loadLibrary("NativeScript");
57-
58-
Logger logger = new LogcatLogger(app);
56+
ManualInstrumentation.Frame frame = ManualInstrumentation.start("RuntimeHelper.initRuntime");
57+
try {
58+
ManualInstrumentation.Frame loadLibraryFrame = ManualInstrumentation.start("loadLibrary NativeScript");
59+
try {
60+
System.loadLibrary("NativeScript");
61+
} finally {
62+
loadLibraryFrame.close();
63+
}
5964

60-
Runtime runtime = null;
61-
boolean showErrorIntent = hasErrorIntent(app);
62-
if (!showErrorIntent) {
63-
NativeScriptUncaughtExceptionHandler exHandler = new NativeScriptUncaughtExceptionHandler(logger, app);
65+
Logger logger = new LogcatLogger(app);
6466

65-
Thread.setDefaultUncaughtExceptionHandler(exHandler);
67+
Runtime runtime = null;
68+
boolean showErrorIntent = hasErrorIntent(app);
69+
if (!showErrorIntent) {
70+
NativeScriptUncaughtExceptionHandler exHandler = new NativeScriptUncaughtExceptionHandler(logger, app);
6671

67-
DefaultExtractPolicy extractPolicy = new DefaultExtractPolicy(logger);
68-
boolean skipAssetExtraction = Util.runPlugin(logger, app);
72+
Thread.setDefaultUncaughtExceptionHandler(exHandler);
6973

70-
String appName = app.getPackageName();
71-
File rootDir = new File(app.getApplicationInfo().dataDir);
72-
File appDir = app.getFilesDir();
74+
DefaultExtractPolicy extractPolicy = new DefaultExtractPolicy(logger);
75+
boolean skipAssetExtraction = Util.runPlugin(logger, app);
7376

74-
try {
75-
appDir = appDir.getCanonicalFile();
76-
} catch (IOException e1) {
77-
}
77+
String appName = app.getPackageName();
78+
File rootDir = new File(app.getApplicationInfo().dataDir);
79+
File appDir = app.getFilesDir();
7880

79-
if (!skipAssetExtraction) {
80-
if (logger.isEnabled()) {
81-
logger.write("Extracting assets...");
81+
try {
82+
appDir = appDir.getCanonicalFile();
83+
} catch (IOException e1) {
8284
}
8385

84-
AssetExtractor aE = new AssetExtractor(null, logger);
86+
if (!skipAssetExtraction) {
87+
ManualInstrumentation.Frame extractionFrame = ManualInstrumentation.start("Extracting assets");
88+
try {
89+
if (logger.isEnabled()) {
90+
logger.write("Extracting assets...");
91+
}
8592

86-
String outputDir = app.getFilesDir().getPath() + File.separator;
93+
AssetExtractor aE = new AssetExtractor(null, logger);
8794

88-
// will force deletion of previously extracted files in app/files directories
89-
// see https://github.com/NativeScript/NativeScript/issues/4137 for reference
90-
boolean removePreviouslyInstalledAssets = true;
91-
aE.extractAssets(app, "app", outputDir, extractPolicy, removePreviouslyInstalledAssets);
92-
aE.extractAssets(app, "internal", outputDir, extractPolicy, removePreviouslyInstalledAssets);
93-
aE.extractAssets(app, "metadata", outputDir, extractPolicy, false);
95+
String outputDir = app.getFilesDir().getPath() + File.separator;
9496

95-
boolean shouldExtractSnapshots = true;
97+
// will force deletion of previously extracted files in app/files directories
98+
// see https://github.com/NativeScript/NativeScript/issues/4137 for reference
99+
boolean removePreviouslyInstalledAssets = true;
100+
aE.extractAssets(app, "app", outputDir, extractPolicy, removePreviouslyInstalledAssets);
101+
aE.extractAssets(app, "internal", outputDir, extractPolicy, removePreviouslyInstalledAssets);
102+
aE.extractAssets(app, "metadata", outputDir, extractPolicy, false);
96103

97-
// will extract snapshot of the device appropriate architecture
98-
if (shouldExtractSnapshots) {
99-
if (logger.isEnabled()) {
100-
logger.write("Extracting snapshot blob");
101-
}
104+
boolean shouldExtractSnapshots = true;
102105

103-
aE.extractAssets(app, "snapshots/" + Build.CPU_ABI, outputDir, extractPolicy, removePreviouslyInstalledAssets);
104-
}
106+
// will extract snapshot of the device appropriate architecture
107+
if (shouldExtractSnapshots) {
108+
if (logger.isEnabled()) {
109+
logger.write("Extracting snapshot blob");
110+
}
105111

106-
extractPolicy.setAssetsThumb(app);
107-
}
112+
aE.extractAssets(app, "snapshots/" + Build.CPU_ABI, outputDir, extractPolicy, removePreviouslyInstalledAssets);
113+
}
108114

109-
AppConfig appConfig = new AppConfig(appDir);
110-
111-
ClassLoader classLoader = app.getClassLoader();
112-
File dexDir = new File(rootDir, "code_cache/secondary-dexes");
113-
String dexThumb = null;
114-
try {
115-
dexThumb = Util.getDexThumb(app);
116-
} catch (NameNotFoundException e) {
117-
if (logger.isEnabled()) {
118-
logger.write("Error while getting current proxy thumb");
115+
extractPolicy.setAssetsThumb(app);
116+
} finally {
117+
extractionFrame.close();
118+
}
119119
}
120-
e.printStackTrace();
121-
}
122-
123-
String nativeLibDir = null;
124-
try {
125-
nativeLibDir = app.getPackageManager().getApplicationInfo(appName, 0).nativeLibraryDir;
126-
} catch (android.content.pm.PackageManager.NameNotFoundException e) {
127-
e.printStackTrace();
128-
}
129120

130-
boolean isDebuggable = Util.isDebuggableApp(app);
131-
StaticConfiguration config = new StaticConfiguration(logger, appName, nativeLibDir, rootDir,
132-
appDir, classLoader, dexDir, dexThumb, appConfig, isDebuggable);
121+
AppConfig appConfig = new AppConfig(appDir);
122+
switch (appConfig.getProfilingMode()) {
123+
case "timeline":
124+
ManualInstrumentation.setMode(ManualInstrumentation.Mode.Timeline);
125+
break;
126+
default:
127+
ManualInstrumentation.setMode(ManualInstrumentation.Mode.Disabled);
128+
}
129+
Runtime.SetManualInstrumentationMode(appConfig.getProfilingMode());
133130

134-
runtime = Runtime.initializeRuntimeWithConfiguration(config);
135-
if (isDebuggable) {
131+
ClassLoader classLoader = app.getClassLoader();
132+
File dexDir = new File(rootDir, "code_cache/secondary-dexes");
133+
String dexThumb = null;
136134
try {
137-
v8Inspector = new AndroidJsV8Inspector(app.getFilesDir().getAbsolutePath(), app.getPackageName());
138-
v8Inspector.start();
139-
140-
// the following snippet is used as means to notify the VSCode extension
141-
// debugger that the debugger agent has started
142-
File debuggerStartedFile = new File("/data/local/tmp", app.getPackageName() + "-debugger-started");
143-
if (debuggerStartedFile.exists() && !debuggerStartedFile.isDirectory() && debuggerStartedFile.length() == 0) {
144-
java.io.FileWriter fileWriter = new java.io.FileWriter(debuggerStartedFile);
145-
fileWriter.write("started");
146-
fileWriter.close();
147-
}
148-
149-
// check if --debug-brk flag has been set. If positive:
150-
// write to the file to invalidate the flag
151-
// inform the v8Inspector to pause the main thread
152-
File debugBreakFile = new File("/data/local/tmp", app.getPackageName() + "-debugbreak");
153-
boolean shouldBreak = false;
154-
if (debugBreakFile.exists() && !debugBreakFile.isDirectory() && debugBreakFile.length() == 0) {
155-
java.io.FileWriter fileWriter = new java.io.FileWriter(debugBreakFile);
156-
fileWriter.write("started");
157-
fileWriter.close();
158-
159-
shouldBreak = true;
135+
dexThumb = Util.getDexThumb(app);
136+
} catch (NameNotFoundException e) {
137+
if (logger.isEnabled()) {
138+
logger.write("Error while getting current proxy thumb");
160139
}
140+
e.printStackTrace();
141+
}
161142

162-
v8Inspector.waitForDebugger(shouldBreak);
163-
} catch (IOException e) {
143+
String nativeLibDir = null;
144+
try {
145+
nativeLibDir = app.getPackageManager().getApplicationInfo(appName, 0).nativeLibraryDir;
146+
} catch (android.content.pm.PackageManager.NameNotFoundException e) {
164147
e.printStackTrace();
165148
}
166-
}
167149

168-
// runtime needs to be initialized before the NativeScriptSyncService is enabled because it uses runtime.runScript(...)
169-
if (NativeScriptSyncService.isSyncEnabled(app)) {
170-
NativeScriptSyncService syncService = new NativeScriptSyncService(runtime, logger, app);
171-
172-
syncService.sync();
173-
syncService.startServer();
174-
175-
// preserve this instance as strong reference
176-
// do not preserve in NativeScriptApplication field inorder to
177-
// make the code more portable
178-
// @@@
179-
// Runtime.getOrCreateJavaObjectID(syncService);
180-
} else {
181-
if (logger.isEnabled()) {
182-
logger.write("NativeScript LiveSync is not enabled.");
150+
boolean isDebuggable = Util.isDebuggableApp(app);
151+
StaticConfiguration config = new StaticConfiguration(logger, appName, nativeLibDir, rootDir,
152+
appDir, classLoader, dexDir, dexThumb, appConfig, isDebuggable);
153+
154+
runtime = Runtime.initializeRuntimeWithConfiguration(config);
155+
if (isDebuggable) {
156+
try {
157+
v8Inspector = new AndroidJsV8Inspector(app.getFilesDir().getAbsolutePath(), app.getPackageName());
158+
v8Inspector.start();
159+
160+
// the following snippet is used as means to notify the VSCode extension
161+
// debugger that the debugger agent has started
162+
File debuggerStartedFile = new File("/data/local/tmp", app.getPackageName() + "-debugger-started");
163+
if (debuggerStartedFile.exists() && !debuggerStartedFile.isDirectory() && debuggerStartedFile.length() == 0) {
164+
java.io.FileWriter fileWriter = new java.io.FileWriter(debuggerStartedFile);
165+
fileWriter.write("started");
166+
fileWriter.close();
167+
}
168+
169+
// check if --debug-brk flag has been set. If positive:
170+
// write to the file to invalidate the flag
171+
// inform the v8Inspector to pause the main thread
172+
File debugBreakFile = new File("/data/local/tmp", app.getPackageName() + "-debugbreak");
173+
boolean shouldBreak = false;
174+
if (debugBreakFile.exists() && !debugBreakFile.isDirectory() && debugBreakFile.length() == 0) {
175+
java.io.FileWriter fileWriter = new java.io.FileWriter(debugBreakFile);
176+
fileWriter.write("started");
177+
fileWriter.close();
178+
179+
shouldBreak = true;
180+
}
181+
182+
v8Inspector.waitForDebugger(shouldBreak);
183+
} catch (IOException e) {
184+
e.printStackTrace();
185+
}
183186
}
184-
}
185187

186-
runtime.runScript(new File(appDir, "internal/ts_helpers.js"));
188+
// runtime needs to be initialized before the NativeScriptSyncService is enabled because it uses runtime.runScript(...)
189+
if (NativeScriptSyncService.isSyncEnabled(app)) {
190+
NativeScriptSyncService syncService = new NativeScriptSyncService(runtime, logger, app);
187191

188-
File javaClassesModule = new File(appDir, "app/tns-java-classes.js");
189-
if (javaClassesModule.exists()) {
190-
runtime.runModule(javaClassesModule);
191-
}
192+
syncService.sync();
193+
syncService.startServer();
192194

193-
try {
194-
// put this call in a try/catch block because with the latest changes in the modules it is not granted that NativeScriptApplication is extended through JavaScript.
195-
JavaScriptImplementation jsImpl = app.getClass().getAnnotation(JavaScriptImplementation.class);
196-
if (jsImpl != null) {
197-
Runtime.initInstance(app);
195+
// preserve this instance as strong reference
196+
// do not preserve in NativeScriptApplication field inorder to
197+
// make the code more portable
198+
// @@@
199+
// Runtime.getOrCreateJavaObjectID(syncService);
200+
} else {
201+
if (logger.isEnabled()) {
202+
logger.write("NativeScript LiveSync is not enabled.");
203+
}
198204
}
199-
} catch (Exception e) {
200-
if (logger.isEnabled()) {
201-
logger.write("Cannot initialize application instance.");
205+
206+
runtime.runScript(new File(appDir, "internal/ts_helpers.js"));
207+
208+
File javaClassesModule = new File(appDir, "app/tns-java-classes.js");
209+
if (javaClassesModule.exists()) {
210+
runtime.runModule(javaClassesModule);
211+
}
212+
213+
try {
214+
// put this call in a try/catch block because with the latest changes in the modules it is not granted that NativeScriptApplication is extended through JavaScript.
215+
JavaScriptImplementation jsImpl = app.getClass().getAnnotation(JavaScriptImplementation.class);
216+
if (jsImpl != null) {
217+
Runtime.initInstance(app);
218+
}
219+
} catch (Exception e) {
220+
if (logger.isEnabled()) {
221+
logger.write("Cannot initialize application instance.");
222+
}
223+
e.printStackTrace();
202224
}
203-
e.printStackTrace();
204225
}
226+
return runtime;
227+
} finally {
228+
frame.close();
205229
}
206-
return runtime;
207230
}
208231

209232
private static final String logTag = "MyApp";

0 commit comments

Comments
 (0)