Skip to content

Commit

Permalink
fix(XLogFileDecode.java): 修复:大文件解密,会发生OOM
Browse files Browse the repository at this point in the history
解密核心:大文件解密,会发生OOM,导致桌面端发生OOM,安卓端由于OOM发生闪退。

Closes #13
  • Loading branch information
zhanlan123 committed Jun 25, 2024
1 parent aa7f633 commit 2b31c76
Show file tree
Hide file tree
Showing 20 changed files with 363 additions and 82 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

# YXLogDecode

![语言](https://img.shields.io/badge/language-C%7CC%2B%2B%7CJava-blue) ![Java](https://img.shields.io/badge/Java-%3E%3D1.8-green) ![Relase](https://img.shields.io/badge/Relase-1.7-yellow)
![语言](https://img.shields.io/badge/language-C%7CC%2B%2B%7CJava-blue) ![Java](https://img.shields.io/badge/Java-%3E%3D1.8-green) ![Relase](https://img.shields.io/badge/Relase-1.9.1-yellow)

**`YXLogDecode`** 是腾讯Mars-xlog的解密的Java实现版本,核心来自<a href="https://github.com/wustMeiming/XlogDecoder">XlogDecoder</a>。
- 支持UI操作;
- 支持压缩加密文件和只压缩文件的解密解压缩;
- 压缩方式支持:ZIP,ZSTD;
- 增加了一个可以在Android上运行的解密核心 **`android/decode-core`**;
- 增加了一个Android上解密查看日志的APP: <a href="https://github.com/zhanlan123/YXlogDecode/releases/download/1.8/XLog_1.8.apk">XLog_1.8.apk</a>;
- 增加了一个Android上解密查看日志的APP: <a href="https://github.com/zhanlan123/YXlogDecode/releases/download/1.9.1/XLog_1.9.1.apk">XLog_1.9.1.apk</a>;

### 目录

Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ android {
applicationId "top.yinlingfeng.xlog.decode"
minSdk 24
targetSdk 33
versionCode 8
versionName "1.8"
versionCode 9
versionName "1.9.1"
ndk {
abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.OpenableColumns;
import android.text.TextUtils;
import android.view.View;
Expand All @@ -20,8 +21,14 @@
import com.blankj.utilcode.util.UriUtils;
import com.hgsoft.log.LogUtil;
import org.apache.commons.lang3.exception.ExceptionUtils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import top.yinlingfeng.xlog.decode.bean.PrivateKey;
import top.yinlingfeng.xlog.decode.constants.MMKVConstants;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,9 @@ object MMKVConstants {

var selectDefaultPrivateKey by PerpetualMMKVOperatingDelegate(MMKVName.SELECT_DEFAULT_PRIVATE_KEY, true)

var splitFileSizeKey by PerpetualMMKVOperatingDelegate(MMKVName.SPLIT_FILE_SIZE_KEY, 30L)

var splitFileStartSizeKey by PerpetualMMKVOperatingDelegate(MMKVName.SPLIT_FILE_START_SIZE_KEY, 50L)

var allHistoryRecord by PerpetualMMKVOperatingDelegate(MMKVName.ALL_HISTORY_RECORD, ArrayList<HistoryRecord>())
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ public class MMKVName {
*/
public static final String SELECT_DEFAULT_PRIVATE_KEY = "select_default_private_key";

/**
* 分割文件大小
*/
public static final String SPLIT_FILE_SIZE_KEY = "split_file_size_key";

/**
* 起始分割文件大小
*/
public static final String SPLIT_FILE_START_SIZE_KEY = "split_file_start_size_key";

/**
* 所有历史记录,
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ protected void onCreate(Bundle savedInstanceState) {
}

private void initView() {
toolbarBinding.tvTitle.setText(R.string.add_private_key);
toolbarBinding.tvTitle.setText(R.string.setting);
toolbarBinding.commonToolbar.setNavigationIcon(R.drawable.back);
toolbarBinding.commonToolbar.setNavigationOnClickListener(v -> {
onBackPressed();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;

import com.blankj.utilcode.util.ToastUtils;
import com.hgsoft.log.LogUtil;
import top.yinlingfeng.xlog.decode.R;
import top.yinlingfeng.xlog.decode.constants.MMKVConstants;
Expand Down Expand Up @@ -32,11 +34,57 @@ private void setClickListener() {
Preference selectPrivateKey = getPreferenceManager().findPreference("select_private_key");
if (selectPrivateKey != null) {
selectPrivateKey.setOnPreferenceChangeListener((preference, newValue) -> {
LogUtil.i(TAG, "Preference:" + preference + ",newValue:" + newValue);
LogUtil.i(TAG, "selectPrivateKey-Preference:" + preference + ",newValue:" + newValue);
MMKVConstants.INSTANCE.setSelectDefaultPrivateKey((boolean) newValue);
return true;
});
}
Preference splitFileStartSizeKey = getPreferenceManager().findPreference("split_file_start_size_key");
if (splitFileStartSizeKey != null) {
splitFileStartSizeKey.setOnPreferenceChangeListener((preference, newValue) -> {
LogUtil.i(TAG, "splitFileStartSizeKey-Preference:" + preference + ",newValue:" + newValue);
int maxFileSize = 100;
String splitFileSizeTxt = (String) newValue;
if (splitFileSizeTxt.length() > 3) {
ToastUtils.showLong("不能超过3位数");
return false;
}
int splitFileSize = Integer.parseInt(splitFileSizeTxt);
if (splitFileSize < 1) {
ToastUtils.showLong("不能小于1");
return false;
}
if (splitFileSize > maxFileSize) {
ToastUtils.showLong("不能超过100");
return false;
}
MMKVConstants.INSTANCE.setSplitFileStartSizeKey(splitFileSize);
return true;
});
}
Preference splitFileKey = getPreferenceManager().findPreference("split_file_key");
if (splitFileKey != null) {
splitFileKey.setOnPreferenceChangeListener((preference, newValue) -> {
LogUtil.i(TAG, "splitFileKey-Preference:" + preference + ",newValue:" + newValue);
int maxFileSize = 100;
String splitFileSizeTxt = (String) newValue;
if (splitFileSizeTxt.length() > 3) {
ToastUtils.showLong("不能超过3位数");
return false;
}
int splitFileSize = Integer.parseInt(splitFileSizeTxt);
if (splitFileSize < 1) {
ToastUtils.showLong("不能小于1");
return false;
}
if (splitFileSize > maxFileSize) {
ToastUtils.showLong("不能超过100");
return false;
}
MMKVConstants.INSTANCE.setSplitFileSizeKey(splitFileSize);
return true;
});
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,26 @@
import androidx.lifecycle.MutableLiveData;
import net.lingala.zip4j.ZipFile;
import org.apache.commons.lang3.exception.ExceptionUtils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;

import top.yinlingfeng.xlog.decode.constants.MMKVConstants;
import top.yinlingfeng.xlog.decode.core.XLogFileDecode;
import top.yinlingfeng.xlog.decode.utils.Event;
import top.yinlingfeng.xlog.decode.utils.ThreadPoolUtils;

import com.blankj.utilcode.util.ConvertUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.hgsoft.log.LogUtil;


Expand Down Expand Up @@ -93,12 +103,14 @@ public void decodeZipXlogFile(InputStream inputStream, String fileName, String p
LogUtil.i(TAG, "复制文件完成-开始解压");
//开始解压
String zipLogFilePath = decodeLogDirPath + "/" + fileName;
String unzipFolderName = "temp";
saveLogFilePath = decodeLogDirPath + File.separator + fileName.substring(0, fileName.lastIndexOf("."));
String saveUnzipLogFilePath = decodeLogDirPath + File.separator + fileName.substring(0, fileName.lastIndexOf(".")) + File.separator + unzipFolderName;;
// 防止因为解压出错,但是实际解压成功,导致不能解密。
ZipFile zipFile = new ZipFile(zipLogFilePath);
zipFile.extractAll(saveLogFilePath);
zipFile.extractAll(saveUnzipLogFilePath);
LogUtil.i(TAG, "解压文件完成-开始获取所有需要解密的文件");
File saveFileDir = new File(saveLogFilePath);
File saveFileDir = new File(saveUnzipLogFilePath);
if (saveFileDir.isDirectory()) {
getAllFilePath(saveFileDir);
} else {
Expand Down Expand Up @@ -142,7 +154,7 @@ public void decodeXlogFile(InputStream inputStream, String fileName, String priv
saveLogFilePath = logPath + "/" + fileName + ".log";
LogUtil.i(TAG, "logFilePath:" + logFilePath);
LogUtil.i(TAG, "saveLogFilePath:" + saveLogFilePath);
XLogFileDecode.parseFile(logFilePath, saveLogFilePath, privateKey);
parseXlogFile(1, logFilePath, saveLogFilePath, privateKey);
LogUtil.i(TAG, "解密文件完成");
_decodeXLogSuccess.postValue(new Event<>(saveLogFilePath));
}
Expand Down Expand Up @@ -221,14 +233,17 @@ private void pollingDecode() throws IOException {

private void startDecodeLogFile(String logFilePath) throws IOException {
LogUtil.i(TAG, "开始解密:" + logFilePath);
String outFilePath = logFilePath + ".log";
File logFile = new File(logFilePath);
String outFilePath = logFile.getParentFile().getParentFile().getAbsolutePath() + File.separator + logFile.getName() + ".log";
LogUtil.i(TAG, "logFilePath:" + logFilePath);
LogUtil.i(TAG, "outFilePath:" + outFilePath);
LogUtil.i(TAG, "privateKey:" + privateKey);
XLogFileDecode.parseFile(logFilePath, outFilePath, privateKey);
parseXlogFile(2, logFilePath, outFilePath, privateKey);
pollingDecode();
}



/**
* 删除历史记录
*/
Expand Down Expand Up @@ -264,4 +279,79 @@ private void deleteAllFile(File file) {
LogUtil.i(TAG, file.getName() + "->删除结果:" + result);
}


/**
* 解密解压缩分割文件
* @param type 分割文件保存目录类型 1:单个文件,2:多个文件
* @param logFilePath 日志路径
* @param outFilePath 输入的日志文件路径
* @param privateKey 私有
* @throws IOException IO异常
*/
private void parseXlogFile(int type, String logFilePath, String outFilePath, String privateKey) throws IOException {
XLogFileDecode.parseFile(logFilePath, outFilePath, privateKey);
splitTxtFile(type, outFilePath);
}

/**
* 分割文件
* @param type 分割文件保存目录类型 1:单个文件,2:多个文件
* @param filePath 需要分割的文件
*/
private void splitTxtFile(int type, String filePath) {
File inputFile = new File(filePath);
long maxFileStartSize = MMKVConstants.INSTANCE.getSplitFileStartSizeKey() * 1024 * 1024;
if (inputFile.length() < maxFileStartSize) {
LogUtil.i(TAG, "不需要进行文件分割!");
return;
}
LogUtil.i(TAG, "开始进行文件分割!");
File externalFileDir = null;
if (type == 1) {
externalFileDir = getApplication().getExternalFilesDir("decodeLog");
} else {
externalFileDir = inputFile.getParentFile();
}
File outputDir = new File(externalFileDir, "split_" + inputFile.getName().substring(0, inputFile.getName().indexOf(".")));


if (!outputDir.exists()) {
outputDir.mkdirs();
}

// 每个文件的最大大小(默认30M)
long maxSplitFileKey = 30;
if (MMKVConstants.INSTANCE.getSplitFileSizeKey() <= 100) {
maxSplitFileKey = MMKVConstants.INSTANCE.getSplitFileSizeKey();
}
long maxFileSize = maxSplitFileKey * 1024 * 1024;
int filePart = 1;

try (BufferedReader reader = new BufferedReader(new FileReader(inputFile))) {
String line;
long currentFileSize = 0;
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(outputDir, ConvertUtils.int2HexString(filePart) + "_" + inputFile.getName())));

while ((line = reader.readLine()) != null) {
byte[] lineBytes = (line + System.lineSeparator()).getBytes();
currentFileSize += lineBytes.length;

if (currentFileSize >= maxFileSize) {
writer.close();
filePart++;
currentFileSize = lineBytes.length;
writer = new BufferedWriter(new FileWriter(new File(outputDir, ConvertUtils.int2HexString(filePart) + "_" + inputFile.getName())));
}

writer.write(line);
writer.newLine();
}
writer.close();
LogUtil.i(TAG, "文件分割完成!");
} catch (IOException e) {
LogUtil.e(TAG, "分割文件失败:" + ExceptionUtils.getStackTrace(e));
ToastUtils.showLong("分割文件失败");
}
}

}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
<string name="import_private_key_success">导入密钥成功</string>
<string name="select_default_private_key_title">默认密钥设置</string>
<string name="select_default_private_key_hint">导入日志解密时是否使用默认选中的密钥?</string>
<string name="split_file_key_title">分割文件</string>
<string name="split_file_start_size_private_key_hint">文件大于多少M需要分割1100M)?</string>
<string name="split_file_default_size_private_key_hint">分割文件的每个文件大小1100M)?</string>
<string name="analysis_file_fail">解析文件失败!</string>
<string name="msg_picked_isnt_dir">选择的路径不是文件夹!</string>
<string name="err_invalid_data_by_intent">Intent 返回了无效数据</string>
Expand Down
17 changes: 16 additions & 1 deletion android/app/src/main/res/xml/preferences.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreferenceCompat
app:icon="@drawable/select_private_key"
app:key="select_private_key"
app:title="@string/select_default_private_key_title"
app:summary="@string/select_default_private_key_hint"
app:defaultValue="true"
/>
<EditTextPreference
android:icon="@drawable/split_file"
android:key="split_file_start_size_key"
android:title="@string/split_file_key_title"
android:summary="@string/split_file_start_size_private_key_hint"
android:inputType="number"
android:defaultValue="50"/>
<EditTextPreference
android:icon="@drawable/split_file"
android:key="split_file_key"
android:title="@string/split_file_key_title"
android:summary="@string/split_file_default_size_private_key_hint"
android:inputType="number"
android:defaultValue="30"/>
</PreferenceScreen>
Loading

0 comments on commit 2b31c76

Please sign in to comment.