meminsight-test-demo 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +36 -0
  3. package/docs/Build.md +68 -0
  4. package/docs/Interface.md +35 -0
  5. package/docs/UserGuide.md +332 -0
  6. package/docs/resources/analyzer.png +0 -0
  7. package/docs/resources/cfg_filter_filetype_json.png +0 -0
  8. package/docs/resources/filetype_txt.png +0 -0
  9. package/docs/resources/framework.png +0 -0
  10. package/docs/resources/output.png +0 -0
  11. package/docs/resources/process.png +0 -0
  12. package/package.json +54 -0
  13. package/packages/cfg/ArkStatCfg.json +33 -0
  14. package/packages/core/jest.config.js +8 -0
  15. package/packages/core/package.json +61 -0
  16. package/packages/core/src/Index.ts +53 -0
  17. package/packages/core/src/analyzer/AnalysisInfo.ts +298 -0
  18. package/packages/core/src/analyzer/ArkAnalyzer.ts +42 -0
  19. package/packages/core/src/analyzer/ArkCmpCfg.ts +22 -0
  20. package/packages/core/src/analyzer/ArkCompareAnalyzer.ts +173 -0
  21. package/packages/core/src/analyzer/ArkLeakAnalyzer.ts +196 -0
  22. package/packages/core/src/analyzer/ArkSerializer.ts +163 -0
  23. package/packages/core/src/analyzer/ArkStatAnalyzer.ts +191 -0
  24. package/packages/core/src/analyzer/ArkStatCfg.ts +77 -0
  25. package/packages/core/src/analyzer/ArkTracePath.ts +269 -0
  26. package/packages/core/src/analyzer/ArkTracer.ts +42 -0
  27. package/packages/core/src/analyzer/ArkXAnalyzer.ts +631 -0
  28. package/packages/core/src/analyzer/IAnalyzer.ts +27 -0
  29. package/packages/core/src/file/FileReader.ts +82 -0
  30. package/packages/core/src/file/FileService.ts +50 -0
  31. package/packages/core/src/file/FileWriter.ts +148 -0
  32. package/packages/core/src/report/Reporter.ts +81 -0
  33. package/packages/core/src/report/templates/template.ejs +101 -0
  34. package/packages/core/src/report/templates/template.ts +103 -0
  35. package/packages/core/src/shell/DeviceShell.ts +179 -0
  36. package/packages/core/src/shell/Shell.ts +99 -0
  37. package/packages/core/src/types/Constants.ts +16 -0
  38. package/packages/core/src/types/LeakTypes.ts +21 -0
  39. package/packages/core/src/types/OhosTypes.ts +115 -0
  40. package/packages/core/src/utils/Common.ts +37 -0
  41. package/packages/core/src/utils/Finder.ts +390 -0
  42. package/packages/core/src/utils/Loader.ts +53 -0
  43. package/packages/core/src/utils/Log.ts +252 -0
  44. package/packages/core/src/utils/Output.ts +271 -0
  45. package/packages/core/tsconfig.json +10 -0
  46. package/packages/exampletools/package.json +52 -0
  47. package/packages/exampletools/src/MemTest.ts +64 -0
  48. package/packages/exampletools/tsconfig.json +15 -0
  49. package/packages/meminsight/jest.config.js +8 -0
  50. package/packages/meminsight/package.json +52 -0
  51. package/packages/meminsight/src/Index.ts +4 -0
  52. package/packages/meminsight/src/Version.ts +7 -0
  53. package/packages/meminsight/src/process/ArkCompareProc.ts +160 -0
  54. package/packages/meminsight/src/process/ArkGCProc.ts +61 -0
  55. package/packages/meminsight/src/process/ArkLeakProc.ts +47 -0
  56. package/packages/meminsight/src/process/ArkStatProc.ts +320 -0
  57. package/packages/meminsight/src/process/ArkXProc.ts +73 -0
  58. package/packages/meminsight/src/process/HMemXProc.ts +50 -0
  59. package/packages/meminsight/src/process/IProcess.ts +12 -0
  60. package/packages/meminsight/tsconfig.json +15 -0
  61. package/packages/stack/README.md +31 -0
  62. package/packages/stack/libs/hstack_lib-1.0.0.tgz +0 -0
  63. package/packages/stack/libs/hstack_lib-1.0.1.tgz +0 -0
  64. package/packages/stack/libs/hstack_lib-1.0.4.tgz +0 -0
  65. package/packages/stack/libs/lib_list.json +34 -0
  66. package/packages/stack/package.json +27 -0
  67. package/packages/stack/src/Index.js +29 -0
  68. package/packages/stack/src/StackTracer.js +53 -0
  69. package/packages/templates/ArkLeaks.template +9 -0
  70. package/packages/templates/ArkNodes.template +9 -0
  71. package/packages/templates/ArkPaths.template +9 -0
  72. package/test/scripts/merge.py +145 -0
  73. package/test/scripts/stat.py +175 -0
  74. package/test/test_ark_stat_proc.sh +14 -0
  75. package/tsconfig.base.json +38 -0
  76. package/tsconfig.json +8 -0
@@ -0,0 +1,179 @@
1
+ import { Shell, ShellArgs } from "./Shell";
2
+ import { AppInfo, DeviceInfo } from "../types/OhosTypes";
3
+
4
+ /**
5
+ * DeviceShell
6
+ */
7
+ export class DeviceShell {
8
+ private static defaultInstance: DeviceShell = new DeviceShell();
9
+ private static deviceMap: Map<string, DeviceShell> = new Map();
10
+ private deviceInfo?: DeviceInfo;
11
+
12
+ constructor(deviceId?: string) {
13
+ this.deviceInfo = new DeviceInfo(deviceId);
14
+ }
15
+
16
+ /**
17
+ * 获取DeviceShell实例
18
+ * @param deviceId device id
19
+ * @returns DeviceShell
20
+ */
21
+ public static getDeviceShell(deviceId?: string) : DeviceShell {
22
+ let shellInst: DeviceShell | undefined = DeviceShell.deviceMap.get(deviceId || '');
23
+ if (!shellInst) {
24
+ shellInst = new DeviceShell(deviceId);
25
+ DeviceShell.deviceMap.set(deviceId || '', shellInst);
26
+ }
27
+ return shellInst;
28
+ }
29
+
30
+ /**
31
+ * clear device shell instances
32
+ */
33
+ public static clearDeviceShell() : void {
34
+ DeviceShell.deviceMap.clear();
35
+ }
36
+
37
+ private getDeviceCmd(): string {
38
+ let deviceId = this.getDeviceId();
39
+ return `${deviceId === '' ? '' : `-t ${deviceId}`}`;
40
+ }
41
+
42
+ /**
43
+ * 默认 DeviceShell 单例
44
+ * @returns device instance
45
+ */
46
+ public static default(): DeviceShell {
47
+ return this.defaultInstance;
48
+ }
49
+
50
+ /**
51
+ * 获取设备信息
52
+ * @returns device info
53
+ */
54
+ public getDeviceInfo(): DeviceInfo | undefined {
55
+ return this.deviceInfo;
56
+ }
57
+
58
+ /**
59
+ * 获取设备ID
60
+ * @returns device id
61
+ */
62
+ public getDeviceId() : string {
63
+ return this.deviceInfo?.deviceId || '';
64
+ }
65
+
66
+ /**
67
+ * 执行设备命令
68
+ * @param cmd command
69
+ * @param excludeEmptyLine 输出不包含空行
70
+ * @param trimLine 输出行去空格
71
+ * @returns 输出信息
72
+ */
73
+ public execSync(cmd: string, excludeEmptyLine: boolean = true, trimLine: boolean = true): string[] {
74
+ let args: ShellArgs = {
75
+ excludeEmptyLine: excludeEmptyLine,
76
+ trimLine: trimLine }
77
+ return Shell.execSync(`hdc ${this.getDeviceCmd()} shell "${cmd}"`, args);
78
+ }
79
+
80
+ /**
81
+ * 接收文件到本地
82
+ * @param remoteFile 远程文件路径
83
+ * @param localFile 本地文件路径
84
+ */
85
+ public recvFile(remoteFile: string, localFile: string): void {
86
+ Shell.execSync(`hdc ${this.getDeviceCmd()} file recv "${remoteFile}" "${localFile}"`);
87
+ }
88
+
89
+ /**
90
+ * 发送文件到设备
91
+ * @param localFile 本地文件路径
92
+ * @param remoteFile 远程文件路径
93
+ */
94
+ public sendFile(localFile: string, remoteFile: string): void {
95
+ Shell.execSync(`hdc ${this.getDeviceCmd()} file send "${localFile}" "${remoteFile}"`);
96
+ }
97
+
98
+ /**
99
+ * 通过应用名称获取app信息
100
+ * @param bundleName 应用名称
101
+ * @returns AppInfo
102
+ */
103
+ public getAppInfoByName(bundleName: string) : AppInfo {
104
+ const appInfo = new AppInfo();
105
+ appInfo.name = bundleName;
106
+ appInfo.pid = this.getAppPid(bundleName);
107
+ return appInfo;
108
+ }
109
+
110
+ /**
111
+ * 通过pid获取app信息
112
+ * @param pid pid
113
+ * @returns AppInfo
114
+ */
115
+ public getAppInfoByPid(pid: number) : AppInfo {
116
+ const appInfo = new AppInfo();
117
+ appInfo.pid = pid;
118
+ appInfo.name = this.getAppName(pid);
119
+ return appInfo;
120
+ }
121
+
122
+ /**
123
+ * 应用进程PID
124
+ * @param bundleName 应用名称
125
+ * @returns pid | undefined
126
+ */
127
+ public getAppPid(bundleName: string) : number | undefined {
128
+ let strs = this.execSync(`pidof ${bundleName}`);
129
+ if (strs.length === 1) {
130
+ return parseInt(strs[0].trim().split(' ')[0]);
131
+ } else {
132
+ return undefined;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * 获取应用名称
138
+ * @param pid 进程id
139
+ * @returns 进程名称
140
+ */
141
+ public getAppName(pid: number) : string {
142
+ // 20008 2940 674 0 12:35:30 ? 00:00:16 com.xxx.yyy.zzz
143
+ let strs = this.execSync(`ps -ef | grep ${pid} | grep -v grep`);
144
+ let appName: string | undefined;
145
+ if (strs.length === 1) {
146
+ appName = strs[0].split(/\s+/).pop();
147
+ }
148
+ return appName || '';
149
+ }
150
+
151
+ /**
152
+ * 是否是Root镜像设备
153
+ * @returns true/false
154
+ */
155
+ public isRootDevice() : boolean {
156
+ let strs = this.execSync('ls /system');
157
+ return strs.findIndex(str => str.indexOf('ls: /system: Permission denied') >= 0) == -1;
158
+ }
159
+
160
+ /**
161
+ * 指定pid GC
162
+ * @param pid 进程id
163
+ */
164
+ public async forceGC(pid: number) : Promise<void> {
165
+ let cmd = `hidumper --mem-jsheap ${pid} --gc`;
166
+ this.execSync(cmd);
167
+ }
168
+
169
+ /**
170
+ * 指定包名 GC
171
+ * @param name 进程名
172
+ */
173
+ public async forceGCByName(app: string) : Promise<void> {
174
+ let pid = this.getAppPid(app);
175
+ if (pid) {
176
+ await this.forceGC(pid);
177
+ }
178
+ }
179
+ }
@@ -0,0 +1,99 @@
1
+ import { execSync, execFileSync, ExecFileSyncOptions } from 'child_process';
2
+
3
+ /**
4
+ * execute args
5
+ */
6
+ export class ShellArgs {
7
+ /**
8
+ * exclude empty line
9
+ */
10
+ excludeEmptyLine: boolean = true;
11
+
12
+ /**
13
+ * trim line start and end
14
+ */
15
+ trimLine: boolean = true;
16
+ }
17
+
18
+ /**
19
+ * shell interface
20
+ */
21
+ export interface IShell {
22
+ /**
23
+ * execute command
24
+ * @param command command
25
+ * @param ExecuteArgs execute args
26
+ */
27
+ execSync(command: string, args?: ShellArgs): string[];
28
+
29
+ /**
30
+ * execute target
31
+ * @param target target path
32
+ * @param ExecuteArgs execute args
33
+ * @param options options
34
+ */
35
+ execSyncTarget(target: string, args?: ShellArgs, options?: ExecFileSyncOptions): string[];
36
+ }
37
+
38
+ /**
39
+ * shell implementation
40
+ */
41
+ class ShellImpl implements IShell {
42
+ /**
43
+ * 执行同步命令
44
+ * @param command 命令
45
+ * @param args 执行参数
46
+ * @returns 输出字符串数组
47
+ */
48
+ execSync(command: string, args?: ShellArgs): string[] {
49
+ let lines = execSync(command).toString("utf-8").split(/\r?\n/);
50
+ if (args) {
51
+ if (args.excludeEmptyLine) {
52
+ lines = lines.filter(line => !!line);
53
+ }
54
+ if (args.trimLine) {
55
+ lines = lines.map(lines => lines.trim())
56
+ }
57
+ }
58
+ return lines;
59
+ }
60
+
61
+ execSyncTarget(target: string, args?: ShellArgs, options?: ExecFileSyncOptions): string[] {
62
+ let lines = execFileSync(target, options).toString('utf-8').split(/\r?\n/);
63
+ if (args) {
64
+ if (args.excludeEmptyLine) {
65
+ lines = lines.filter(line => !!line);
66
+ }
67
+ if (args.trimLine) {
68
+ lines = lines.map(lines => lines.trim())
69
+ }
70
+ }
71
+ return lines;
72
+ }
73
+ }
74
+
75
+ /**
76
+ * shell wrapper
77
+ */
78
+ export class Shell {
79
+ private static _impl: IShell = new ShellImpl();
80
+
81
+ /**
82
+ * execute command
83
+ * @param command commanda
84
+ * @param formatArgs output format args
85
+ */
86
+ public static execSync(command: string, args?: ShellArgs): string[] {
87
+ return this._impl.execSync(command, args);
88
+ }
89
+
90
+ /**
91
+ * execute target
92
+ * @param target target path
93
+ * @param args args
94
+ * @param options options
95
+ */
96
+ public static execSyncTarget(target: string, args?: ShellArgs, options?: ExecFileSyncOptions): string[] {
97
+ return this._impl.execSyncTarget(target, args, options);
98
+ }
99
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * strings enum
3
+ */
4
+ export enum STRINGS {
5
+ IS_DELETING = 'isDeleting_',
6
+ BOOLEAN_TRUE = 'Boolean:true',
7
+
8
+ OBJECT = '(object)',
9
+ CLOSURE = '(closure)',
10
+ FUNCTION = '(function)',
11
+ ARRAY = '(array)',
12
+ STRING = '(string)',
13
+
14
+ CONSTRUCTOR = 'constructor',
15
+ PROTO = '__proto__',
16
+ }
@@ -0,0 +1,21 @@
1
+ import { LeakTracePathItem } from '@memlab/core'
2
+
3
+ export interface ILeakBase {
4
+ nodeId: number;
5
+ startTime: number;
6
+ endTime: number;
7
+ duration?: number; // leaked duration
8
+ }
9
+
10
+ export interface ILeakTrace extends ILeakBase {
11
+ trace: LeakTracePathItem,
12
+ }
13
+
14
+ export interface ILeakUnit extends ILeakBase {
15
+ trace: string[];
16
+ }
17
+
18
+ export interface ILeakResult {
19
+ related: Map<any, any>;
20
+ leaks: ILeakUnit[];
21
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * interface for data info
3
+ */
4
+ export interface IDataInfo {
5
+ type: string;
6
+ toString(): string;
7
+ }
8
+
9
+ /**
10
+ * os info
11
+ */
12
+ export class OsInfo implements IDataInfo {
13
+ public type: string = "os";
14
+ public name: string;
15
+ public version?: string;
16
+
17
+ constructor(name?: string, version?: string) {
18
+ this.name = name || "ohos";
19
+ this.version = version;
20
+ }
21
+
22
+ public toString(): string {
23
+ return `${this.type} ${this.name} ${this.version}`;
24
+ }
25
+ }
26
+
27
+ /**
28
+ * device info
29
+ */
30
+ export class DeviceInfo implements IDataInfo {
31
+ public type: string = 'ohos-device';
32
+ public deviceId: string;
33
+ public deviceName?: string;
34
+ public version?: string;
35
+
36
+ constructor(deviceId?: string) {
37
+ this.deviceId = deviceId || '';
38
+ }
39
+
40
+ public toString(): string {
41
+ return `${this.deviceId}`;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * app info
47
+ */
48
+ export class AppInfo implements IDataInfo {
49
+ public type: string = 'app';
50
+ public name: string;
51
+ public pid?: number;
52
+ public version?: string;
53
+
54
+ constructor(name?: string, pid?: number, version?: string) {
55
+ this.name = name || '';
56
+ this.pid = pid;
57
+ this.version = version;
58
+ }
59
+
60
+ public toString(): string {
61
+ return `${this.name}`;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * url info
67
+ */
68
+ export class UrlInfo implements IDataInfo {
69
+ public type: string = 'url';
70
+ public url: string;
71
+ public mappingUrl?: string;
72
+
73
+ public toString(): string {
74
+ return `${this.url}`;
75
+ }
76
+ }
77
+
78
+ /**
79
+ * heap file info
80
+ */
81
+ export class HeapFileInfo implements IDataInfo {
82
+ public type: string = 'heap';
83
+ public name: string;
84
+ public path: string;
85
+ public size?: number;
86
+ public region?: string;
87
+ public scene?: string;
88
+ public url?: UrlInfo;
89
+ public createTime?: number = 0; // create time
90
+
91
+ constructor(path: string) {
92
+ this.path = path;
93
+ }
94
+
95
+ public toString(): string {
96
+ return `${this.name}:${this.path}`;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * heap infos
102
+ */
103
+ export class HeapInfos {
104
+ public osInfo?: OsInfo;
105
+ public deviceInfo?: DeviceInfo;
106
+ public appInfo?: AppInfo;
107
+ public heapFileInfo?: HeapFileInfo;
108
+
109
+ constructor(os?: OsInfo, device?: DeviceInfo, app?: AppInfo, heapFile?: HeapFileInfo) {
110
+ this.osInfo = os;
111
+ this.deviceInfo = device;
112
+ this.appInfo = app;
113
+ this.heapFileInfo = heapFile;
114
+ }
115
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * T != null
3
+ * @param value T instance
4
+ * @returns true if T instance is not null or undefined
5
+ */
6
+ export function isDefined<T>(value: T | null | undefined): value is T {
7
+ return value != null;
8
+ }
9
+
10
+ /**
11
+ * 格式化 Date 为指定字符串
12
+ * @param date 要格式化的日期(默认当前时间)
13
+ * @param format 格式模板:YYYY=年, MM=月, DD=日, HH=时, mm=分, ss=秒, SSS=毫秒
14
+ * @returns 格式化后的字符串
15
+ */
16
+ export function formatDate(date: Date, format: string = 'YYYYMMDDHHmmss'): string {
17
+ // 补零函数:确保数字为两位数(如 9 → 09)
18
+ const padZero = (num: number, length = 2): string => num.toString().padStart(length, '0');
19
+
20
+ const year = date.getFullYear();
21
+ const month = padZero(date.getMonth() + 1); // 月份从 0 开始,需 +1
22
+ const day = padZero(date.getDate());
23
+ const hour = padZero(date.getHours());
24
+ const minute = padZero(date.getMinutes());
25
+ const second = padZero(date.getSeconds());
26
+ const millisecond = padZero(date.getMilliseconds(), 3); // 三位数毫秒
27
+
28
+ // 替换格式模板
29
+ return format
30
+ .replace('YYYY', year.toString())
31
+ .replace('MM', month)
32
+ .replace('DD', day)
33
+ .replace('HH', hour)
34
+ .replace('mm', minute)
35
+ .replace('ss', second)
36
+ .replace('SSS', millisecond);
37
+ }