Skip to content

Commit

Permalink
[hapjs-platform#629]沙箱fix:调试器打开性能面板,查看日志面板,log输出异常,一直打印error、warning日志
Browse files Browse the repository at this point in the history
  • Loading branch information
jianghai33 committed Dec 12, 2023
1 parent 5e7c04e commit b813ca0
Show file tree
Hide file tree
Showing 9 changed files with 406 additions and 133 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* Copyright (C) 2023, hapjs.org. All rights reserved.
*/
package org.hapjs.analyzer.model;

parcelable LogData;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright (C) 2023, hapjs.org. All rights reserved.
*/

package org.hapjs.runtime.sandbox;

import org.hapjs.analyzer.model.LogData;

interface ILogListener {
void onLog(in List<LogData> logs);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ package org.hapjs.runtime.sandbox;

import android.os.ParcelFileDescriptor;

import org.hapjs.runtime.sandbox.ILogListener;
import org.hapjs.runtime.sandbox.ILogProvider;

interface ISandbox {
void init(in Map configs);
ParcelFileDescriptor[] createChannel(in ParcelFileDescriptor[] readSide);
void setLogProvider(ILogProvider logProvider);
void setLogListener(ILogListener listener);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2023, hapjs.org. All rights reserved.
*/
package org.hapjs.analyzer.model;

import android.os.Parcel;
import android.os.Parcelable;

public class LogData implements Parcelable {
public @LogPackage.LogLevel
int mLevel;
public @LogPackage.LogType
int mType;
public String mContent;

public LogData(@LogPackage.LogLevel int level, @LogPackage.LogType int type, String content) {
mLevel = level;
mType = type;
mContent = content;
}

protected LogData(Parcel in) {
mLevel = in.readInt();
mType = in.readInt();
mContent = in.readString();
}

public static final Creator<LogData> CREATOR = new Creator<LogData>() {
@Override
public LogData createFromParcel(Parcel in) {
return new LogData(in);
}

@Override
public LogData[] newArray(int size) {
return new LogData[size];
}
};

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mLevel);
dest.writeInt(mType);
dest.writeString(mContent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,6 @@ public LogPackage(int position, List<LogData> datas) {
this.datas = datas;
}

public static class LogData {
public @LogLevel int mLevel;
public @LogType int mType;
public String mContent;

public LogData(@LogLevel int level, @LogType int type, String content) {
mLevel = level;
mType = type;
mContent = content;
}
}

@IntDef({LOG_LEVEL_DEFAULT, Log.VERBOSE, Log.DEBUG, Log.INFO, Log.WARN, Log.ERROR})
public @interface LogLevel {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
/*
* Copyright (C) 2023, hapjs.org. All rights reserved.
*/
package org.hapjs.analyzer.monitors;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.hapjs.analyzer.model.LogData;
import org.hapjs.analyzer.model.LogPackage;
import org.hapjs.common.executors.Executors;
import org.hapjs.common.utils.FileUtils;

public abstract class AbsLogDumper implements Runnable {
protected static final String STR_DUMP_FAIL = "--- LOGCAT_CONSOLE dump log fail ! ---";
private static final int DUMP_LOG_INTERVAL = 100;
private static final int DUMP_LOG_BATCH_CNT = 100;
private static final int MSG_DUMP_LOG = 0;

private java.lang.Process mLogcatProcess;
private boolean mIsStop;
private List<LogData> mPendingLogs = new ArrayList<>();
private final Handler mMainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_DUMP_LOG) {
List<LogData> pendingLogs = new ArrayList<>();
synchronized (AbsLogDumper.this) {
pendingLogs.addAll(mPendingLogs);
mPendingLogs.clear();
}
doDumpLog(pendingLogs);
}
}
};

void clearLogcat() {
Executors.io().execute(new Runnable() {
@Override
public void run() {
java.lang.Process process = null;
try {
process = Runtime.getRuntime().exec("logcat -b main -c");
Thread.sleep(1000);
} catch (Exception e) {
// ignore
} finally {
if (process != null) {
process.destroy();
}
}
}
});
}

private BufferedReader getLogReader() throws IOException {
String command = "logcat -b main -v time --pid " + android.os.Process.myPid();
if (mLogcatProcess != null) {
mLogcatProcess.destroy();
}
mLogcatProcess = Runtime.getRuntime().exec(command);
return new BufferedReader(new InputStreamReader(mLogcatProcess.getInputStream(), StandardCharsets.UTF_8));
}

@Override
public void run() {
BufferedReader reader = null;
try {
String line;
reader = getLogReader();
while (!mIsStop) {
line = reader.readLine();
if (line == null) {
dumpFailLog();
break;
} else {
dumpLog(line);
}
}
} catch (Exception e) {
// ignore
} finally {
FileUtils.closeQuietly(reader);
}
}

private void dumpLog(String log) {
int logLevel = getLogLevel(log);
boolean isJsLog = log.contains(LogcatMonitor.JS_TAG);
LogData logData = new LogData(logLevel, isJsLog ? LogPackage.LOG_TYPE_JS : LogPackage.LOG_TYPE_NATIVE, log);
dumpLog(logData);
}

public void dumpFailLog() {
LogData logData = new LogData(LogPackage.LOG_LEVEL_DEFAULT, LogPackage.LOG_TYPE_DEFAULT, STR_DUMP_FAIL);
dumpLog(logData);
}

private synchronized void dumpLog(LogData log) {
List<LogData> logs = new ArrayList<>();
logs.add(log);
dumpLog(logs);
}

protected synchronized void dumpLog(List<LogData> logs) {
boolean noPending = mPendingLogs.isEmpty();
mPendingLogs = mergeLogs(mPendingLogs, logs);
if (noPending) {
if (!mMainHandler.hasMessages(MSG_DUMP_LOG)) {
mMainHandler.sendEmptyMessageDelayed(MSG_DUMP_LOG, DUMP_LOG_INTERVAL);
}
} else if (mPendingLogs.size() > DUMP_LOG_BATCH_CNT) {
if (!mMainHandler.hasMessages(MSG_DUMP_LOG)) {
mMainHandler.sendEmptyMessage(MSG_DUMP_LOG);
}
}
}

private static List<LogData> mergeLogs(List<LogData> logs1, List<LogData> logs2) {
if (logs1 == null || logs1.isEmpty()) {
return logs2;
}
if (logs2 == null || logs2.isEmpty()) {
return logs1;
}
if (compareTimestamp(logs1.get(logs1.size() - 1), logs2.get(0)) <= 0) {
logs1.addAll(logs2);
return logs1;
}
if (compareTimestamp(logs2.get(logs2.size() - 1), logs1.get(0)) <= 0) {
logs2.addAll(logs1);
return logs2;
}

List<LogData> mergedLogs = new ArrayList<>();
for (int i = 0, j = 0; i < logs1.size() || j < logs2.size(); ) {
if (i >= logs1.size()) {
mergedLogs.add(logs2.get(j++));
} else if (j >= logs2.size()) {
mergedLogs.add(logs1.get(i++));
} else if (compareTimestamp(logs1.get(i), logs2.get(j)) <= 0) {
mergedLogs.add(logs1.get(i++));
} else {
mergedLogs.add(logs2.get(j++));
}
}
return mergedLogs;
}

private static int compareTimestamp(LogData logData1, LogData logData2) {
return getTimestamp(logData1).compareTo(getTimestamp(logData2));
}

private static String getTimestamp(LogData logData) {
int length = logData.mContent.length();
return logData.mContent.substring(0, Math.min(length, 18));
}

protected abstract void doDumpLog(List<LogData> log);

public void close() {
mIsStop = true;
clearLogcat();
closeLogcatProcess();
}

private void closeLogcatProcess() {
if (mLogcatProcess != null) {
try {
mLogcatProcess.destroy();
} catch (Exception e) {
// ignore
}
}
mLogcatProcess = null;
}

private @LogPackage.LogLevel int getLogLevel(String log) {
if (log.length() < 20) {
return Log.VERBOSE;
}
char level = log.charAt(19);
switch (level) {
case 'V':
return Log.VERBOSE;
case 'D':
return Log.DEBUG;
case 'I':
return Log.INFO;
case 'W':
return Log.WARN;
case 'E':
return Log.ERROR;
}
return Log.VERBOSE;
}
}
Loading

0 comments on commit b813ca0

Please sign in to comment.