fix bugs
This commit is contained in:
parent
a4dc7ff1e8
commit
fda90e332a
|
@ -100,7 +100,11 @@
|
||||||
android:screenOrientation="sensorLandscape"/>
|
android:screenOrientation="sensorLandscape"/>
|
||||||
<service
|
<service
|
||||||
android:name="com.tungsten.fclcore.download.ProcessService"
|
android:name="com.tungsten.fclcore.download.ProcessService"
|
||||||
android:process=":processService" />
|
android:process=":processService"
|
||||||
|
android:launchMode="standard"
|
||||||
|
android:multiprocess="true"
|
||||||
|
android:alwaysRetainTaskState="true"
|
||||||
|
android:enabled="true"/>
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="@string/file_browser_provider"
|
android:authorities="@string/file_browser_provider"
|
||||||
|
|
|
@ -33,6 +33,7 @@ import com.tungsten.fclcore.event.Event;
|
||||||
import com.tungsten.fclcore.fakefx.beans.property.ObjectProperty;
|
import com.tungsten.fclcore.fakefx.beans.property.ObjectProperty;
|
||||||
import com.tungsten.fclcore.fakefx.beans.property.SimpleObjectProperty;
|
import com.tungsten.fclcore.fakefx.beans.property.SimpleObjectProperty;
|
||||||
import com.tungsten.fclcore.fakefx.beans.value.ObservableValue;
|
import com.tungsten.fclcore.fakefx.beans.value.ObservableValue;
|
||||||
|
import com.tungsten.fclcore.task.Schedulers;
|
||||||
import com.tungsten.fclcore.util.Logging;
|
import com.tungsten.fclcore.util.Logging;
|
||||||
import com.tungsten.fclcore.util.fakefx.BindingMapping;
|
import com.tungsten.fclcore.util.fakefx.BindingMapping;
|
||||||
import com.tungsten.fcllibrary.component.FCLActivity;
|
import com.tungsten.fcllibrary.component.FCLActivity;
|
||||||
|
@ -306,6 +307,6 @@ public class MainActivity extends FCLActivity implements FCLMenuView.OnSelectLis
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupVersionDisplay() {
|
private void setupVersionDisplay() {
|
||||||
holder.add(FXUtils.onWeakChangeAndOperate(Profiles.selectedVersionProperty(), this::loadVersion));
|
holder.add(FXUtils.onWeakChangeAndOperate(Profiles.selectedVersionProperty(), s -> Schedulers.androidUIThread().execute(() -> loadVersion(s))));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ import static com.tungsten.fclcore.util.Lang.tryCast;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -40,6 +41,7 @@ import com.tungsten.fclcore.task.TaskListener;
|
||||||
import com.tungsten.fclcore.util.Lang;
|
import com.tungsten.fclcore.util.Lang;
|
||||||
import com.tungsten.fclcore.util.StringUtils;
|
import com.tungsten.fclcore.util.StringUtils;
|
||||||
import com.tungsten.fcllibrary.component.FCLAdapter;
|
import com.tungsten.fcllibrary.component.FCLAdapter;
|
||||||
|
import com.tungsten.fcllibrary.component.theme.ThemeEngine;
|
||||||
import com.tungsten.fcllibrary.component.view.FCLImageView;
|
import com.tungsten.fcllibrary.component.view.FCLImageView;
|
||||||
import com.tungsten.fcllibrary.component.view.FCLProgressBar;
|
import com.tungsten.fcllibrary.component.view.FCLProgressBar;
|
||||||
import com.tungsten.fcllibrary.component.view.FCLTextView;
|
import com.tungsten.fcllibrary.component.view.FCLTextView;
|
||||||
|
@ -225,6 +227,16 @@ public final class TaskListPane extends FCLAdapter {
|
||||||
title = parent.findViewById(R.id.title);
|
title = parent.findViewById(R.id.title);
|
||||||
icon = parent.findViewById(R.id.icon);
|
icon = parent.findViewById(R.id.icon);
|
||||||
|
|
||||||
|
int[][] state = {
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
int[] color = {
|
||||||
|
ThemeEngine.getSystemAutoTint(context)
|
||||||
|
};
|
||||||
|
icon.setImageTintList(new ColorStateList(state, color));
|
||||||
|
|
||||||
String stageKey = StringUtils.substringBefore(stage, ':');
|
String stageKey = StringUtils.substringBefore(stage, ':');
|
||||||
String stageValue = StringUtils.substringAfter(stage, ':');
|
String stageValue = StringUtils.substringAfter(stage, ':');
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package com.tungsten.fclcore.download;
|
package com.tungsten.fclcore.download;
|
||||||
|
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
@ -10,7 +9,6 @@ import androidx.annotation.Nullable;
|
||||||
import com.tungsten.fclauncher.FCLConfig;
|
import com.tungsten.fclauncher.FCLConfig;
|
||||||
import com.tungsten.fclauncher.FCLauncher;
|
import com.tungsten.fclauncher.FCLauncher;
|
||||||
import com.tungsten.fclauncher.bridge.FCLBridgeCallback;
|
import com.tungsten.fclauncher.bridge.FCLBridgeCallback;
|
||||||
import com.tungsten.fclauncher.FCLPath;
|
|
||||||
|
|
||||||
import java.net.DatagramPacket;
|
import java.net.DatagramPacket;
|
||||||
import java.net.DatagramSocket;
|
import java.net.DatagramSocket;
|
||||||
|
@ -28,13 +26,20 @@ public class ProcessService extends Service {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
FCLPath.loadPaths(getApplicationContext());
|
System.out.println("ProcessService started!");
|
||||||
String[] commands = intent.getExtras().getStringArray("commands");
|
String[] command = intent.getExtras().getStringArray("command");
|
||||||
startProcess(getApplicationContext(), commands);
|
FCLConfig config = new FCLConfig(
|
||||||
|
getApplicationContext(),
|
||||||
|
getApplicationContext().getExternalFilesDir("log").getAbsolutePath(),
|
||||||
|
getApplicationContext().getDir("runtime", 0).getAbsolutePath() + "/java/jre8",
|
||||||
|
getApplicationContext().getCacheDir() + "/fclauncher",
|
||||||
|
null,
|
||||||
|
command);
|
||||||
|
startProcess(config);
|
||||||
return super.onStartCommand(intent, flags, startId);
|
return super.onStartCommand(intent, flags, startId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startProcess(Context context, String[] args) {
|
public void startProcess(FCLConfig config) {
|
||||||
FCLBridgeCallback callback = new FCLBridgeCallback() {
|
FCLBridgeCallback callback = new FCLBridgeCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onCursorModeChange(int mode) {
|
public void onCursorModeChange(int mode) {
|
||||||
|
@ -56,13 +61,6 @@ public class ProcessService extends Service {
|
||||||
android.os.Process.killProcess(android.os.Process.myPid());
|
android.os.Process.killProcess(android.os.Process.myPid());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
FCLConfig config = new FCLConfig(
|
|
||||||
context,
|
|
||||||
FCLPath.LOG_DIR,
|
|
||||||
FCLPath.JAVA_8_PATH,
|
|
||||||
FCLPath.CACHE_DIR,
|
|
||||||
null,
|
|
||||||
args);
|
|
||||||
FCLauncher.launchAPIInstaller(config, callback);
|
FCLauncher.launchAPIInstaller(config, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.jar.Attributes;
|
import java.util.jar.Attributes;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
|
@ -140,9 +141,11 @@ public class ForgeNewInstallTask extends Task<Version> {
|
||||||
|
|
||||||
LOG.info("Executing external processor " + processor.getJar().toString() + ", command line: " + new CommandBuilder().addAll(command).toString());
|
LOG.info("Executing external processor " + processor.getJar().toString() + ", command line: " + new CommandBuilder().addAll(command).toString());
|
||||||
int exitCode;
|
int exitCode;
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
SocketServer server = new SocketServer("127.0.0.1", ProcessService.PROCESS_SERVICE_PORT, (server1, msg) -> {
|
SocketServer server = new SocketServer("127.0.0.1", ProcessService.PROCESS_SERVICE_PORT, (server1, msg) -> {
|
||||||
server1.setResult(msg);
|
server1.setResult(msg);
|
||||||
server1.stop();
|
server1.stop();
|
||||||
|
latch.countDown();
|
||||||
});
|
});
|
||||||
Intent service = new Intent(FCLPath.CONTEXT, ProcessService.class);
|
Intent service = new Intent(FCLPath.CONTEXT, ProcessService.class);
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
|
@ -150,6 +153,7 @@ public class ForgeNewInstallTask extends Task<Version> {
|
||||||
service.putExtras(bundle);
|
service.putExtras(bundle);
|
||||||
FCLPath.CONTEXT.startService(service);
|
FCLPath.CONTEXT.startService(service);
|
||||||
server.start();
|
server.start();
|
||||||
|
latch.await();
|
||||||
exitCode = (int) server.getResult();
|
exitCode = (int) server.getResult();
|
||||||
if (exitCode != 0)
|
if (exitCode != 0)
|
||||||
throw new IOException("Game processor exited abnormally with code " + exitCode);
|
throw new IOException("Game processor exited abnormally with code " + exitCode);
|
||||||
|
|
|
@ -6,6 +6,7 @@ import com.tungsten.fclcore.game.Library;
|
||||||
import com.tungsten.fclcore.game.Version;
|
import com.tungsten.fclcore.game.Version;
|
||||||
import com.tungsten.fclcore.task.FileDownloadTask;
|
import com.tungsten.fclcore.task.FileDownloadTask;
|
||||||
import com.tungsten.fclcore.task.Task;
|
import com.tungsten.fclcore.task.Task;
|
||||||
|
import com.tungsten.fclcore.util.LibFilter;
|
||||||
import com.tungsten.fclcore.util.Logging;
|
import com.tungsten.fclcore.util.Logging;
|
||||||
import com.tungsten.fclcore.util.io.FileUtils;
|
import com.tungsten.fclcore.util.io.FileUtils;
|
||||||
|
|
||||||
|
@ -46,9 +47,9 @@ public final class GameLibrariesTask extends Task<Void> {
|
||||||
*/
|
*/
|
||||||
public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version, boolean integrityCheck, List<Library> libraries) {
|
public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version, boolean integrityCheck, List<Library> libraries) {
|
||||||
this.dependencyManager = dependencyManager;
|
this.dependencyManager = dependencyManager;
|
||||||
this.version = version;
|
this.version = LibFilter.filter(version);
|
||||||
this.integrityCheck = integrityCheck;
|
this.integrityCheck = integrityCheck;
|
||||||
this.libraries = libraries;
|
this.libraries = LibFilter.filterLibs(libraries);
|
||||||
|
|
||||||
setSignificance(TaskSignificance.MODERATE);
|
setSignificance(TaskSignificance.MODERATE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class LibraryDownloadTask extends Task<Void> {
|
||||||
else
|
else
|
||||||
throw new LibraryDownloadException(library, t);
|
throw new LibraryDownloadException(library, t);
|
||||||
} else {
|
} else {
|
||||||
if (xz) unpackLibrary(jar, Files.readAllBytes(xzFile.toPath()));
|
// if (xz) unpackLibrary(jar, Files.readAllBytes(xzFile.toPath()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +255,8 @@ public class LibraryDownloadTask extends Task<Void> {
|
||||||
jos.closeEntry();
|
jos.closeEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (temp.toFile().exists()) {
|
||||||
Files.delete(temp);
|
Files.delete(temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import java.nio.file.FileSystem;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Note</b>: OptiFine should be installed in the end.
|
* <b>Note</b>: OptiFine should be installed in the end.
|
||||||
|
@ -141,16 +142,19 @@ public final class OptiFineInstallTask extends Task<Version> {
|
||||||
gameRepository.getLibraryFile(version, optiFineLibrary).toString()
|
gameRepository.getLibraryFile(version, optiFineLibrary).toString()
|
||||||
};
|
};
|
||||||
int exitCode;
|
int exitCode;
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
SocketServer server = new SocketServer("127.0.0.1", ProcessService.PROCESS_SERVICE_PORT, (server1, msg) -> {
|
SocketServer server = new SocketServer("127.0.0.1", ProcessService.PROCESS_SERVICE_PORT, (server1, msg) -> {
|
||||||
server1.setResult(msg);
|
server1.setResult(msg);
|
||||||
server1.stop();
|
server1.stop();
|
||||||
|
latch.countDown();
|
||||||
});
|
});
|
||||||
Intent service = new Intent(FCLPath.CONTEXT, ProcessService.class);
|
Intent service = new Intent(FCLPath.CONTEXT, ProcessService.class);
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putStringArray("commands", command);
|
bundle.putStringArray("command", command);
|
||||||
service.putExtras(bundle);
|
service.putExtras(bundle);
|
||||||
FCLPath.CONTEXT.startService(service);
|
FCLPath.CONTEXT.startService(service);
|
||||||
server.start();
|
server.start();
|
||||||
|
latch.await();
|
||||||
exitCode = (int) server.getResult();
|
exitCode = (int) server.getResult();
|
||||||
if (exitCode != 0)
|
if (exitCode != 0)
|
||||||
throw new IOException("OptiFine patcher failed, command: " + new CommandBuilder().addAll(Arrays.asList(command)));
|
throw new IOException("OptiFine patcher failed, command: " + new CommandBuilder().addAll(Arrays.asList(command)));
|
||||||
|
|
|
@ -4,17 +4,22 @@ import com.tungsten.fclcore.game.Library;
|
||||||
import com.tungsten.fclcore.game.Version;
|
import com.tungsten.fclcore.game.Version;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class LibFilter {
|
public class LibFilter {
|
||||||
|
|
||||||
public static Version filter(Version version) {
|
public static Version filter(Version version) {
|
||||||
|
return version.setLibraries(filterLibs(version.getLibraries()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Library> filterLibs(List<Library> libraries) {
|
||||||
ArrayList<Library> newLibraries = new ArrayList<>();
|
ArrayList<Library> newLibraries = new ArrayList<>();
|
||||||
for (Library library : version.getLibraries()) {
|
for (Library library : libraries) {
|
||||||
if (!library.isNative() && !library.getName().contains("net.java.jinput") && !library.getName().contains("org.lwjgl") && !library.getName().contains("platform")) {
|
if (!library.isNative() && !library.getName().contains("net.java.jinput") && !library.getName().contains("org.lwjgl") && !library.getName().contains("platform")) {
|
||||||
newLibraries.add(library);
|
newLibraries.add(library);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return version.setLibraries(newLibraries);
|
return newLibraries;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.tungsten.fclcore.util;
|
package com.tungsten.fclcore.util;
|
||||||
|
|
||||||
|
import com.tungsten.fclcore.task.Schedulers;
|
||||||
|
|
||||||
import java.net.DatagramPacket;
|
import java.net.DatagramPacket;
|
||||||
import java.net.DatagramSocket;
|
import java.net.DatagramSocket;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -11,8 +13,8 @@ import java.util.logging.Level;
|
||||||
|
|
||||||
public class SocketServer {
|
public class SocketServer {
|
||||||
|
|
||||||
private final DatagramPacket packet;
|
private DatagramPacket packet;
|
||||||
private final DatagramSocket socket;
|
private DatagramSocket socket;
|
||||||
private final Listener listener;
|
private final Listener listener;
|
||||||
private final String ip;
|
private final String ip;
|
||||||
private final int port;
|
private final int port;
|
||||||
|
@ -24,13 +26,19 @@ public class SocketServer {
|
||||||
void onReceive(SocketServer server, String msg);
|
void onReceive(SocketServer server, String msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SocketServer(String ip, int port, Listener listener) throws UnknownHostException, SocketException {
|
public SocketServer(String ip, int port, Listener listener) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
|
Schedulers.androidUIThread().execute(() -> {
|
||||||
byte[] bytes = new byte[1024];
|
byte[] bytes = new byte[1024];
|
||||||
packet = new DatagramPacket(bytes, bytes.length);
|
packet = new DatagramPacket(bytes, bytes.length);
|
||||||
|
try {
|
||||||
socket = new DatagramSocket(port, InetAddress.getByName(ip));
|
socket = new DatagramSocket(port, InetAddress.getByName(ip));
|
||||||
|
} catch (SocketException | UnknownHostException e) {
|
||||||
|
Logging.LOG.log(Level.WARNING, "Failed to start socket server, error: " + e.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DatagramPacket getPacket() {
|
public DatagramPacket getPacket() {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
@ -61,6 +62,14 @@ public class ThemeEngine {
|
||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isNightMode(Context context) {
|
||||||
|
return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getSystemAutoTint(Context context) {
|
||||||
|
return isNightMode(context) ? Color.WHITE : Color.BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
public void applyColor(int color) {
|
public void applyColor(int color) {
|
||||||
theme.setColor(color);
|
theme.setColor(color);
|
||||||
for (View view : runnables.keySet()) {
|
for (View view : runnables.keySet()) {
|
||||||
|
|
|
@ -2,9 +2,11 @@ package com.tungsten.fclauncher;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
public class FCLConfig {
|
import java.io.Serializable;
|
||||||
|
|
||||||
public enum Renderer {
|
public class FCLConfig implements Serializable {
|
||||||
|
|
||||||
|
public enum Renderer implements Serializable {
|
||||||
RENDERER_GL4ES("libgl4es.so:libgl4es_egl.so"),
|
RENDERER_GL4ES("libgl4es.so:libgl4es_egl.so"),
|
||||||
RENDERER_ZINK("libGL.so:libEGL.so");
|
RENDERER_ZINK("libGL.so:libEGL.so");
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,8 @@ public class FCLauncher {
|
||||||
argList.add(0, config.getJavaPath() + "/bin/java");
|
argList.add(0, config.getJavaPath() + "/bin/java");
|
||||||
String[] args = new String[argList.size()];
|
String[] args = new String[argList.size()];
|
||||||
for (int i = 0; i < argList.size(); i++) {
|
for (int i = 0; i < argList.size(); i++) {
|
||||||
args[i] = argList.get(i).replace("${natives_directory}", getLibraryPath(config.getContext(), config.getJavaPath())).replace("${gl_lib_name}", config.getRenderer().getGlLibName());
|
String a = argList.get(i).replace("${natives_directory}", getLibraryPath(config.getContext(), config.getJavaPath()));
|
||||||
|
args[i] = config.getRenderer() == null ? a : a.replace("${gl_lib_name}", config.getRenderer().getGlLibName());
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
@ -179,6 +180,24 @@ public class FCLauncher {
|
||||||
bridge.dlopen(jreLibDir + "/libfontmanager.so");
|
bridge.dlopen(jreLibDir + "/libfontmanager.so");
|
||||||
bridge.dlopen(jreLibDir + "/libtinyiconv.so");
|
bridge.dlopen(jreLibDir + "/libtinyiconv.so");
|
||||||
bridge.dlopen(jreLibDir + "/libinstrument.so");
|
bridge.dlopen(jreLibDir + "/libinstrument.so");
|
||||||
|
for(File file : locateLibs(new File(config.getJavaPath()))) {
|
||||||
|
bridge.dlopen(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayList<File> locateLibs(File path) {
|
||||||
|
ArrayList<File> returnValue = new ArrayList<>();
|
||||||
|
File[] list = path.listFiles();
|
||||||
|
if (list != null) {
|
||||||
|
for (File f : list) {
|
||||||
|
if (f.isFile() && f.getName().endsWith(".so")) {
|
||||||
|
returnValue.add(f);
|
||||||
|
} else if(f.isDirectory()) {
|
||||||
|
returnValue.addAll(locateLibs(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setupGraphicAndSoundEngine(FCLConfig config, FCLBridge bridge) {
|
private static void setupGraphicAndSoundEngine(FCLConfig config, FCLBridge bridge) {
|
||||||
|
@ -203,6 +222,8 @@ public class FCLauncher {
|
||||||
System.out.println(task + " argument: " + arg);
|
System.out.println(task + " argument: " + arg);
|
||||||
}
|
}
|
||||||
bridge.setupJLI();
|
bridge.setupJLI();
|
||||||
|
bridge.setLdLibraryPath(getLibraryPath(config.getContext(), config.getJavaPath()));
|
||||||
|
System.out.println("Hook exit " + (bridge.setupExitTrap(bridge) == 0 ? "success" : "failed"));
|
||||||
System.out.println("OpenJDK exited with code : " + bridge.jliLaunch(args));
|
System.out.println("OpenJDK exited with code : " + bridge.jliLaunch(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,9 +248,6 @@ public class FCLauncher {
|
||||||
// setup graphic and sound engine
|
// setup graphic and sound engine
|
||||||
setupGraphicAndSoundEngine(config, bridge);
|
setupGraphicAndSoundEngine(config, bridge);
|
||||||
|
|
||||||
// hook exit
|
|
||||||
bridge.setupExitTrap(bridge);
|
|
||||||
|
|
||||||
// set working directory
|
// set working directory
|
||||||
System.out.println("Working directory: " + config.getWorkingDir());
|
System.out.println("Working directory: " + config.getWorkingDir());
|
||||||
bridge.chdir(config.getWorkingDir());
|
bridge.chdir(config.getWorkingDir());
|
||||||
|
@ -268,9 +286,6 @@ public class FCLauncher {
|
||||||
// setup graphic and sound engine
|
// setup graphic and sound engine
|
||||||
setupGraphicAndSoundEngine(config, bridge);
|
setupGraphicAndSoundEngine(config, bridge);
|
||||||
|
|
||||||
// hook exit
|
|
||||||
bridge.setupExitTrap(bridge);
|
|
||||||
|
|
||||||
// set working directory
|
// set working directory
|
||||||
System.out.println("Working directory: " + config.getWorkingDir());
|
System.out.println("Working directory: " + config.getWorkingDir());
|
||||||
bridge.chdir(config.getWorkingDir());
|
bridge.chdir(config.getWorkingDir());
|
||||||
|
@ -305,9 +320,6 @@ public class FCLauncher {
|
||||||
// setup java runtime
|
// setup java runtime
|
||||||
setUpJavaRuntime(config, bridge);
|
setUpJavaRuntime(config, bridge);
|
||||||
|
|
||||||
// hook exit
|
|
||||||
bridge.setupExitTrap(bridge);
|
|
||||||
|
|
||||||
// set working directory
|
// set working directory
|
||||||
System.out.println("Working directory: " + config.getWorkingDir());
|
System.out.println("Working directory: " + config.getWorkingDir());
|
||||||
bridge.chdir(config.getWorkingDir());
|
bridge.chdir(config.getWorkingDir());
|
||||||
|
|
|
@ -60,7 +60,8 @@ public class FCLBridge implements Serializable {
|
||||||
public native int chdir(String path);
|
public native int chdir(String path);
|
||||||
public native void setenv(String key, String value);
|
public native void setenv(String key, String value);
|
||||||
public native int dlopen(String path);
|
public native int dlopen(String path);
|
||||||
public native void setupExitTrap(FCLBridge bridge);
|
public native void setLdLibraryPath(String path);
|
||||||
|
public native int setupExitTrap(FCLBridge bridge);
|
||||||
public native void setEventPipe();
|
public native void setEventPipe();
|
||||||
public native void pushEvent(long time, int type, int keycode, int keyChar);
|
public native void pushEvent(long time, int type, int keycode, int keyChar);
|
||||||
public native void setupJLI();
|
public native void setupJLI();
|
||||||
|
@ -108,7 +109,7 @@ public class FCLBridge implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loader function
|
// Loader function
|
||||||
public void exit(int code) {
|
public void onExit(int code) {
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.onExit(code);
|
callback.onExit(code);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,21 +23,12 @@ static const jboolean const_cpwildcard = JNI_TRUE;
|
||||||
static const jboolean const_javaw = JNI_FALSE;
|
static const jboolean const_javaw = JNI_FALSE;
|
||||||
static const jint const_ergo_class = 0; //DEFAULT_POLICY
|
static const jint const_ergo_class = 0; //DEFAULT_POLICY
|
||||||
|
|
||||||
|
typedef void (*android_update_LD_LIBRARY_PATH_t)(const char*);
|
||||||
static volatile jobject exitTrap_bridge;
|
static volatile jobject exitTrap_bridge;
|
||||||
static volatile jmethodID exitTrap_method;
|
static volatile jmethodID exitTrap_method;
|
||||||
static JavaVM *exitTrap_jvm;
|
static JavaVM *exitTrap_jvm;
|
||||||
|
|
||||||
void (*old_exit)(int code);
|
JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_redirectStdio(JNIEnv* env, jobject jobject, jstring path) {
|
||||||
void custom_exit(int code) {
|
|
||||||
JNIEnv *env;
|
|
||||||
(*exitTrap_jvm)->AttachCurrentThread(exitTrap_jvm, &env, NULL);
|
|
||||||
(*env)->CallVoidMethod(env, exitTrap_bridge, exitTrap_method, code);
|
|
||||||
(*env)->DeleteGlobalRef(env, exitTrap_bridge);
|
|
||||||
(*exitTrap_jvm)->DetachCurrentThread(exitTrap_jvm);
|
|
||||||
old_exit(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_redirectStdio(JNIEnv* env, jclass clazz, jstring path) {
|
|
||||||
char const* file = (*env)->GetStringUTFChars(env, path, 0);
|
char const* file = (*env)->GetStringUTFChars(env, path, 0);
|
||||||
|
|
||||||
int fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
int fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
|
@ -47,7 +38,7 @@ JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_redirectStd
|
||||||
(*env)->ReleaseStringUTFChars(env, path, file);
|
(*env)->ReleaseStringUTFChars(env, path, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_chdir(JNIEnv* env, jclass clazz, jstring path) {
|
JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_chdir(JNIEnv* env, jobject jobject, jstring path) {
|
||||||
char const* dir = (*env)->GetStringUTFChars(env, path, 0);
|
char const* dir = (*env)->GetStringUTFChars(env, path, 0);
|
||||||
|
|
||||||
int b = chdir(dir);
|
int b = chdir(dir);
|
||||||
|
@ -56,7 +47,7 @@ JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_chdir(JNIEn
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setenv(JNIEnv* env, jclass clazz, jstring str1, jstring str2) {
|
JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setenv(JNIEnv* env, jobject jobject, jstring str1, jstring str2) {
|
||||||
char const* name = (*env)->GetStringUTFChars(env, str1, 0);
|
char const* name = (*env)->GetStringUTFChars(env, str1, 0);
|
||||||
char const* value = (*env)->GetStringUTFChars(env, str2, 0);
|
char const* value = (*env)->GetStringUTFChars(env, str2, 0);
|
||||||
|
|
||||||
|
@ -66,7 +57,7 @@ JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setenv(JNIE
|
||||||
(*env)->ReleaseStringUTFChars(env, str2, value);
|
(*env)->ReleaseStringUTFChars(env, str2, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_dlopen(JNIEnv* env, jclass clazz, jstring str) {
|
JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_dlopen(JNIEnv* env, jobject jobject, jstring str) {
|
||||||
dlerror();
|
dlerror();
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -74,7 +65,7 @@ JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_dlopen(JNIE
|
||||||
|
|
||||||
void* handle;
|
void* handle;
|
||||||
dlerror();
|
dlerror();
|
||||||
handle = dlopen(lib_name, RTLD_GLOBAL);
|
handle = dlopen(lib_name, RTLD_GLOBAL | RTLD_LAZY);
|
||||||
__android_log_print(dlerror() == NULL ? ANDROID_LOG_INFO : ANDROID_LOG_ERROR, "FCL", "loading %s (error = %s)", lib_name, dlerror());
|
__android_log_print(dlerror() == NULL ? ANDROID_LOG_INFO : ANDROID_LOG_ERROR, "FCL", "loading %s (error = %s)", lib_name, dlerror());
|
||||||
|
|
||||||
if (handle == NULL) {
|
if (handle == NULL) {
|
||||||
|
@ -85,15 +76,40 @@ JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_dlopen(JNIE
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setupExitTrap(JNIEnv *env, jclass clazz, jobject bridge) {
|
JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setLdLibraryPath(JNIEnv *env, jobject jobject, jstring ldLibraryPath) {
|
||||||
|
android_update_LD_LIBRARY_PATH_t android_update_LD_LIBRARY_PATH;
|
||||||
|
void *libdl_handle = dlopen("libdl.so", RTLD_LAZY);
|
||||||
|
void *updateLdLibPath = dlsym(libdl_handle, "android_update_LD_LIBRARY_PATH");
|
||||||
|
if (updateLdLibPath == NULL) {
|
||||||
|
updateLdLibPath = dlsym(libdl_handle, "__loader_android_update_LD_LIBRARY_PATH");
|
||||||
|
__android_log_print(dlerror() == NULL ? ANDROID_LOG_INFO : ANDROID_LOG_ERROR, "FCL", "loading %s (error = %s)", "libdl.so", dlerror());
|
||||||
|
}
|
||||||
|
android_update_LD_LIBRARY_PATH = (android_update_LD_LIBRARY_PATH_t) updateLdLibPath;
|
||||||
|
const char* ldLibPathUtf = (*env)->GetStringUTFChars(env, ldLibraryPath, 0);
|
||||||
|
android_update_LD_LIBRARY_PATH(ldLibPathUtf);
|
||||||
|
(*env)->ReleaseStringUTFChars(env, ldLibraryPath, ldLibPathUtf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*old_exit)(int code);
|
||||||
|
void custom_exit(int code) {
|
||||||
|
__android_log_print(code == 0 ? ANDROID_LOG_INFO : ANDROID_LOG_ERROR, "FCL", "JVM exit with code %d.", code);
|
||||||
|
JNIEnv *env;
|
||||||
|
(*exitTrap_jvm)->AttachCurrentThread(exitTrap_jvm, &env, NULL);
|
||||||
|
(*env)->CallVoidMethod(env, exitTrap_bridge, exitTrap_method, code);
|
||||||
|
(*env)->DeleteGlobalRef(env, exitTrap_bridge);
|
||||||
|
(*exitTrap_jvm)->DetachCurrentThread(exitTrap_jvm);
|
||||||
|
old_exit(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setupExitTrap(JNIEnv *env, jobject jobject1, jobject bridge) {
|
||||||
exitTrap_bridge = (*env)->NewGlobalRef(env, bridge);
|
exitTrap_bridge = (*env)->NewGlobalRef(env, bridge);
|
||||||
(*env)->GetJavaVM(env, &exitTrap_jvm);
|
(*env)->GetJavaVM(env, &exitTrap_jvm);
|
||||||
jclass exitTrap_exitClass = (*env)->NewGlobalRef(env,(*env)->FindClass(env, "com/tungsten/fclauncher/bridge/FCLBridge"));
|
jclass exitTrap_exitClass = (*env)->NewGlobalRef(env,(*env)->FindClass(env, "com/tungsten/fclauncher/bridge/FCLBridge"));
|
||||||
exitTrap_method = (*env)->GetMethodID(env, exitTrap_exitClass, "exit", "(I)V");
|
exitTrap_method = (*env)->GetMethodID(env, exitTrap_exitClass, "onExit", "(I)V");
|
||||||
(*env)->DeleteGlobalRef(env, exitTrap_exitClass);
|
(*env)->DeleteGlobalRef(env, exitTrap_exitClass);
|
||||||
// xhook_enable_debug(1);
|
xhook_enable_debug(1);
|
||||||
xhook_register(".*\\.so$", "exit", custom_exit, (void **) &old_exit);
|
xhook_register(".*\\.so$", "exit", custom_exit, (void **) &old_exit);
|
||||||
xhook_refresh(1);
|
return xhook_refresh(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -110,7 +126,7 @@ int
|
||||||
jint ergo_class /* ergnomics policy */
|
jint ergo_class /* ergnomics policy */
|
||||||
);
|
);
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setupJLI(JNIEnv* env, jclass clazz){
|
JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setupJLI(JNIEnv* env, jobject jobject){
|
||||||
|
|
||||||
void* handle;
|
void* handle;
|
||||||
handle = dlopen("libjli.so", RTLD_LAZY);
|
handle = dlopen("libjli.so", RTLD_LAZY);
|
||||||
|
@ -118,7 +134,7 @@ JNIEXPORT void JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_setupJLI(JN
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_jliLaunch(JNIEnv *env, jclass clazz, jobjectArray argsArray){
|
JNIEXPORT jint JNICALL Java_com_tungsten_fclauncher_bridge_FCLBridge_jliLaunch(JNIEnv *env, jobject jobject, jobjectArray argsArray){
|
||||||
int argc = (*env)->GetArrayLength(env, argsArray);
|
int argc = (*env)->GetArrayLength(env, argsArray);
|
||||||
char* argv[argc];
|
char* argv[argc];
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
|
|
|
@ -306,14 +306,10 @@ static void xh_core_refresh_impl()
|
||||||
char line[512];
|
char line[512];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
uintptr_t base_addr;
|
uintptr_t base_addr;
|
||||||
uintptr_t prev_base_addr = 0;
|
|
||||||
char perm[5];
|
char perm[5];
|
||||||
char prev_perm[5] = "---p";
|
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
unsigned long prev_offset = 0;
|
|
||||||
int pathname_pos;
|
int pathname_pos;
|
||||||
char *pathname;
|
char *pathname;
|
||||||
char prev_pathname[512] = {0};
|
|
||||||
size_t pathname_len;
|
size_t pathname_len;
|
||||||
xh_core_map_info_t *mi, *mi_tmp;
|
xh_core_map_info_t *mi, *mi_tmp;
|
||||||
xh_core_map_info_t mi_key;
|
xh_core_map_info_t mi_key;
|
||||||
|
@ -332,12 +328,16 @@ static void xh_core_refresh_impl()
|
||||||
{
|
{
|
||||||
if(sscanf(line, "%"PRIxPTR"-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue;
|
if(sscanf(line, "%"PRIxPTR"-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue;
|
||||||
|
|
||||||
// do not touch the shared memory
|
//check permission
|
||||||
if (perm[3] != 'p') continue;
|
if(perm[0] != 'r') continue;
|
||||||
|
if(perm[3] != 'p') continue; //do not touch the shared memory
|
||||||
|
|
||||||
// Ignore permission PROT_NONE maps
|
//check offset
|
||||||
if (perm[0] == '-' && perm[1] == '-' && perm[2] == '-')
|
//
|
||||||
continue;
|
//We are trying to find ELF header in memory.
|
||||||
|
//It can only be found at the beginning of a mapped memory regions
|
||||||
|
//whose offset is 0.
|
||||||
|
if(0 != offset) continue;
|
||||||
|
|
||||||
//get pathname
|
//get pathname
|
||||||
while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1))
|
while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1))
|
||||||
|
@ -354,26 +354,6 @@ static void xh_core_refresh_impl()
|
||||||
if(0 == pathname_len) continue;
|
if(0 == pathname_len) continue;
|
||||||
if('[' == pathname[0]) continue;
|
if('[' == pathname[0]) continue;
|
||||||
|
|
||||||
// Find non-executable map, we need record it. Because so maps can begin with
|
|
||||||
// an non-executable map.
|
|
||||||
if (perm[2] != 'x') {
|
|
||||||
prev_offset = offset;
|
|
||||||
prev_base_addr = base_addr;
|
|
||||||
memcpy(prev_perm, perm, sizeof(prev_perm));
|
|
||||||
strcpy(prev_pathname, pathname);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find executable map if offset == 0, it OK,
|
|
||||||
// or we need check previous map for base address.
|
|
||||||
if (offset != 0) {
|
|
||||||
if (strcmp(prev_pathname, pathname) || prev_offset != 0 || prev_perm[0] != 'r') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// The previous map is real begin map
|
|
||||||
base_addr = prev_base_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//check pathname
|
//check pathname
|
||||||
//if we need to hook this elf?
|
//if we need to hook this elf?
|
||||||
match = 0;
|
match = 0;
|
||||||
|
|
Loading…
Reference in New Issue