feat: add output log to media
底層實現了日誌檔案寫入。為管理器新增了 outputLog 選項,可以將日誌輸出到 Android/media 目錄。
This commit is contained in:
parent
02c9d34f5a
commit
7613e7de10
|
|
@ -109,6 +109,9 @@ jobs:
|
||||||
echo 'android.native.buildOutput=verbose'
|
echo 'android.native.buildOutput=verbose'
|
||||||
} >> gradle.properties
|
} >> gradle.properties
|
||||||
|
|
||||||
|
- name: Grant execution permission to gradlew
|
||||||
|
run: chmod +x gradlew
|
||||||
|
|
||||||
- name: Build dependencies with Gradle
|
- name: Build dependencies with Gradle
|
||||||
working-directory: libxposed
|
working-directory: libxposed
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@
|
||||||
branch = android10-release
|
branch = android10-release
|
||||||
[submodule "core"]
|
[submodule "core"]
|
||||||
path = core
|
path = core
|
||||||
url = https://github.com/JingMatrix/LSPosed.git
|
url = https://github.com/HSSkyBoy/LSPosed.git
|
||||||
branch = master
|
branch = master
|
||||||
|
|
|
||||||
2
core
2
core
|
|
@ -1 +1 @@
|
||||||
Subproject commit fd894b94b2c0790f69aed8b75f13d2cc4f5c26b9
|
Subproject commit b168c71f7b05b81a05cefc8343ca10bfb5fb1dc9
|
||||||
|
|
@ -359,6 +359,14 @@ private fun PatchOptionsBody(modifier: Modifier, onAddEmbed: () -> Unit) {
|
||||||
desc = stringResource(R.string.patch_inject_dex_desc)
|
desc = stringResource(R.string.patch_inject_dex_desc)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SettingsCheckBox(
|
||||||
|
modifier = Modifier.clickable { viewModel.outputLog = !viewModel.outputLog },
|
||||||
|
checked = viewModel.outputLog,
|
||||||
|
icon = Icons.Outlined.AddCard,
|
||||||
|
title = stringResource(R.string.patch_output_log_to_media),
|
||||||
|
desc = stringResource(R.string.patch_output_log_to_media_desc)
|
||||||
|
)
|
||||||
|
|
||||||
var bypassExpanded by remember { mutableStateOf(false) }
|
var bypassExpanded by remember { mutableStateOf(false) }
|
||||||
AnywhereDropdown(
|
AnywhereDropdown(
|
||||||
expanded = bypassExpanded,
|
expanded = bypassExpanded,
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,10 @@ fun checkIsApkFixedByLSP(context: Context, packageName: String): Boolean {
|
||||||
context.packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
|
context.packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
|
||||||
(app.metaData?.containsKey("lspatch") != true)
|
(app.metaData?.containsKey("lspatch") != true)
|
||||||
} catch (_: PackageManager.NameNotFoundException) {
|
} catch (_: PackageManager.NameNotFoundException) {
|
||||||
Log.e("LSPatch", "Package not found: $packageName")
|
Log.e("NPatch", "Package not found: $packageName")
|
||||||
false
|
false
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("LSPatch", "Unexpected error in checkIsApkFixedByLSP", e)
|
Log.e("NPatch", "Unexpected error in checkIsApkFixedByLSP", e)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ class NewPatchViewModel : ViewModel() {
|
||||||
var overrideVersionCode by mutableStateOf(false)
|
var overrideVersionCode by mutableStateOf(false)
|
||||||
var sigBypassLevel by mutableStateOf(2)
|
var sigBypassLevel by mutableStateOf(2)
|
||||||
var injectDex by mutableStateOf(false)
|
var injectDex by mutableStateOf(false)
|
||||||
|
var outputLog by mutableStateOf(true)
|
||||||
var embeddedModules = emptyList<AppInfo>()
|
var embeddedModules = emptyList<AppInfo>()
|
||||||
|
|
||||||
lateinit var patchApp: AppInfo
|
lateinit var patchApp: AppInfo
|
||||||
|
|
@ -96,7 +97,7 @@ class NewPatchViewModel : ViewModel() {
|
||||||
if (useManager) embeddedModules = emptyList()
|
if (useManager) embeddedModules = emptyList()
|
||||||
patchOptions = Patcher.Options(
|
patchOptions = Patcher.Options(
|
||||||
injectDex = injectDex,
|
injectDex = injectDex,
|
||||||
config = PatchConfig(useManager, debuggable, overrideVersionCode, sigBypassLevel, null, null),
|
config = PatchConfig(useManager, debuggable, overrideVersionCode, sigBypassLevel, null, null, outputLog),
|
||||||
apkPaths = listOf(patchApp.app.sourceDir) + (patchApp.app.splitSourceDirs ?: emptyArray()),
|
apkPaths = listOf(patchApp.app.sourceDir) + (patchApp.app.splitSourceDirs ?: emptyArray()),
|
||||||
embeddedModules = embeddedModules.flatMap { listOf(it.app.sourceDir) + (it.app.splitSourceDirs ?: emptyArray()) }
|
embeddedModules = embeddedModules.flatMap { listOf(it.app.sourceDir) + (it.app.splitSourceDirs ?: emptyArray()) }
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,9 @@ public class LSPApplication {
|
||||||
// WARN: Since it uses `XResource`, the following class should not be initialized
|
// WARN: Since it uses `XResource`, the following class should not be initialized
|
||||||
// before forkPostCommon is invoke. Otherwise, you will get failure of XResources
|
// before forkPostCommon is invoke. Otherwise, you will get failure of XResources
|
||||||
|
|
||||||
|
if (config.outputLog){
|
||||||
|
XposedBridge.setLogPrinter(new XposedLogPrinter(0,"NPatch"));
|
||||||
|
}
|
||||||
Log.i(TAG, "Load modules");
|
Log.i(TAG, "Load modules");
|
||||||
LSPLoader.initModules(appLoadedApk);
|
LSPLoader.initModules(appLoadedApk);
|
||||||
Log.i(TAG, "Modules initialized");
|
Log.i(TAG, "Modules initialized");
|
||||||
|
|
@ -119,7 +122,7 @@ public class LSPApplication {
|
||||||
switchAllClassLoader();
|
switchAllClassLoader();
|
||||||
SigBypass.doSigBypass(context, config.sigBypassLevel);
|
SigBypass.doSigBypass(context, config.sigBypassLevel);
|
||||||
|
|
||||||
Log.i(TAG, "LSPatch bootstrap completed");
|
Log.i(TAG, "NPatch bootstrap completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Context createLoadedApkWithContext() {
|
private static Context createLoadedApkWithContext() {
|
||||||
|
|
@ -142,7 +145,7 @@ public class LSPApplication {
|
||||||
Log.i(TAG, "Use manager: " + config.useManager);
|
Log.i(TAG, "Use manager: " + config.useManager);
|
||||||
Log.i(TAG, "Signature bypass level: " + config.sigBypassLevel);
|
Log.i(TAG, "Signature bypass level: " + config.sigBypassLevel);
|
||||||
|
|
||||||
Path originPath = Paths.get(appInfo.dataDir, "cache/lspatch/origin/");
|
Path originPath = Paths.get(appInfo.dataDir, "cache/npatch/origin/");
|
||||||
Path cacheApkPath;
|
Path cacheApkPath;
|
||||||
try (ZipFile sourceFile = new ZipFile(appInfo.sourceDir)) {
|
try (ZipFile sourceFile = new ZipFile(appInfo.sourceDir)) {
|
||||||
cacheApkPath = originPath.resolve(sourceFile.getEntry(ORIGINAL_APK_ASSET_PATH).getCrc() + ".apk");
|
cacheApkPath = originPath.resolve(sourceFile.getEntry(ORIGINAL_APK_ASSET_PATH).getCrc() + ".apk");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package org.lsposed.lspatch.loader;
|
||||||
|
|
||||||
|
import android.app.ActivityThread;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.LogPrinter;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class XposedLogPrinter extends LogPrinter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Printer that sends to the log with the given priority
|
||||||
|
* and tag.
|
||||||
|
*
|
||||||
|
* @param priority The desired log priority:
|
||||||
|
* {@link Log#VERBOSE Log.VERBOSE},
|
||||||
|
* {@link Log#DEBUG Log.DEBUG},
|
||||||
|
* {@link Log#INFO Log.INFO},
|
||||||
|
* {@link Log#WARN Log.WARN}, or
|
||||||
|
* {@link Log#ERROR Log.ERROR}.
|
||||||
|
* @param tag A string tag to associate with each printed log statement.
|
||||||
|
*/
|
||||||
|
public XposedLogPrinter(int priority, String tag) {
|
||||||
|
super(priority, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(String x) {
|
||||||
|
writeLine(x);
|
||||||
|
}
|
||||||
|
private static SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
|
||||||
|
private static FileOutputStream out;
|
||||||
|
private static synchronized void writeLine(String text){
|
||||||
|
try {
|
||||||
|
if (out == null){
|
||||||
|
File f = new File(Environment.getExternalStorageDirectory() + "/Android/media/" + ActivityThread.currentPackageName() + "/npatch/log/");
|
||||||
|
f.mkdirs();
|
||||||
|
out = new FileOutputStream(new File(f,format.format(new Date()) + ".log"),true);
|
||||||
|
}
|
||||||
|
out.write(text.getBytes());
|
||||||
|
out.write("\n".getBytes());
|
||||||
|
}catch (Exception ignored){ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -81,6 +81,9 @@ public class LSPatch {
|
||||||
@Parameter(names = {"--injectdex"}, description = "Inject directly the loder dex file into the original application package")
|
@Parameter(names = {"--injectdex"}, description = "Inject directly the loder dex file into the original application package")
|
||||||
private boolean injectDex = false;
|
private boolean injectDex = false;
|
||||||
|
|
||||||
|
@Parameter(names = {"--outputLog"}, description = "Output Log to Media")
|
||||||
|
private boolean outputLog = true;
|
||||||
|
|
||||||
@Parameter(names = {"-k", "--keystore"}, arity = 4, description = "Set custom signature keystore. Followed by 4 arguments: keystore path, keystore password, keystore alias, keystore alias password")
|
@Parameter(names = {"-k", "--keystore"}, arity = 4, description = "Set custom signature keystore. Followed by 4 arguments: keystore path, keystore password, keystore alias, keystore alias password")
|
||||||
private List<String> keystoreArgs = Arrays.asList(null, "123456", "key0", "123456");
|
private List<String> keystoreArgs = Arrays.asList(null, "123456", "key0", "123456");
|
||||||
|
|
||||||
|
|
@ -96,6 +99,7 @@ public class LSPatch {
|
||||||
@Parameter(names = {"-m", "--embed"}, description = "Embed provided modules to apk")
|
@Parameter(names = {"-m", "--embed"}, description = "Embed provided modules to apk")
|
||||||
private List<String> modules = new ArrayList<>();
|
private List<String> modules = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
private static final String ANDROID_MANIFEST_XML = "AndroidManifest.xml";
|
private static final String ANDROID_MANIFEST_XML = "AndroidManifest.xml";
|
||||||
private static final HashSet<String> ARCHES = new HashSet<>(Arrays.asList(
|
private static final HashSet<String> ARCHES = new HashSet<>(Arrays.asList(
|
||||||
"armeabi-v7a",
|
"armeabi-v7a",
|
||||||
|
|
@ -250,7 +254,7 @@ public class LSPatch {
|
||||||
|
|
||||||
logger.i("Patching apk...");
|
logger.i("Patching apk...");
|
||||||
// modify manifest
|
// modify manifest
|
||||||
final var config = new PatchConfig(useManager, debuggableFlag, overrideVersionCode, sigbypassLevel, originalSignature, appComponentFactory);
|
final var config = new PatchConfig(useManager, debuggableFlag, overrideVersionCode, sigbypassLevel, originalSignature, appComponentFactory, outputLog);
|
||||||
final var configBytes = new Gson().toJson(config).getBytes(StandardCharsets.UTF_8);
|
final var configBytes = new Gson().toJson(config).getBytes(StandardCharsets.UTF_8);
|
||||||
final var metadata = Base64.getEncoder().encodeToString(configBytes);
|
final var metadata = Base64.getEncoder().encodeToString(configBytes);
|
||||||
try (var is = new ByteArrayInputStream(modifyManifestFile(manifestEntry.open(), metadata, minSdkVersion))) {
|
try (var is = new ByteArrayInputStream(modifyManifestFile(manifestEntry.open(), metadata, minSdkVersion))) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ public class PatchConfig {
|
||||||
public final boolean useManager;
|
public final boolean useManager;
|
||||||
public final boolean debuggable;
|
public final boolean debuggable;
|
||||||
public final boolean overrideVersionCode;
|
public final boolean overrideVersionCode;
|
||||||
|
public final boolean outputLog;
|
||||||
public final int sigBypassLevel;
|
public final int sigBypassLevel;
|
||||||
public final String originalSignature;
|
public final String originalSignature;
|
||||||
public final String appComponentFactory;
|
public final String appComponentFactory;
|
||||||
|
|
@ -17,7 +18,8 @@ public class PatchConfig {
|
||||||
boolean overrideVersionCode,
|
boolean overrideVersionCode,
|
||||||
int sigBypassLevel,
|
int sigBypassLevel,
|
||||||
String originalSignature,
|
String originalSignature,
|
||||||
String appComponentFactory
|
String appComponentFactory,
|
||||||
|
boolean outputLog
|
||||||
) {
|
) {
|
||||||
this.useManager = useManager;
|
this.useManager = useManager;
|
||||||
this.debuggable = debuggable;
|
this.debuggable = debuggable;
|
||||||
|
|
@ -27,5 +29,6 @@ public class PatchConfig {
|
||||||
this.appComponentFactory = appComponentFactory;
|
this.appComponentFactory = appComponentFactory;
|
||||||
this.lspConfig = LSPConfig.instance;
|
this.lspConfig = LSPConfig.instance;
|
||||||
this.managerPackageName = Constants.MANAGER_PACKAGE_NAME;
|
this.managerPackageName = Constants.MANAGER_PACKAGE_NAME;
|
||||||
|
this.outputLog = outputLog;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue