emulator on android: crashes but APKs are building
This commit is contained in:
+6
-7
@@ -7,7 +7,7 @@ default-run = "emulator"
|
||||
[lib]
|
||||
name = "dsa_rs"
|
||||
path = "src/lib.rs"
|
||||
type = "cdylib"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[[bin]]
|
||||
name = "emulator"
|
||||
@@ -25,17 +25,16 @@ toml = { version = "0.8.23", optional = true }
|
||||
serde = { version = "1.0.219", features = ["derive"], optional = true }
|
||||
egui_file = "0.22.1"
|
||||
|
||||
[features]
|
||||
default = ["config"]
|
||||
discord-rpc = ["dep:discord-presence"]
|
||||
config = ["dep:toml", "dep:serde"]
|
||||
|
||||
# Add support for Android for the fun of it.
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
winit = { version = "0.30.11", features = ["android-native-activity"] }
|
||||
# jni = "0.21.1"
|
||||
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies.eframe]
|
||||
version = "0.31.1"
|
||||
features = ["android-native-activity"]
|
||||
|
||||
[features]
|
||||
default = ["config"]
|
||||
discord-rpc = ["dep:discord-presence"]
|
||||
config = ["dep:toml", "dep:serde"]
|
||||
|
||||
@@ -13,3 +13,117 @@
|
||||
)]
|
||||
|
||||
pub mod emulator;
|
||||
|
||||
use std::{
|
||||
sync::{
|
||||
Arc,
|
||||
mpsc::{Receiver, Sender},
|
||||
},
|
||||
thread,
|
||||
};
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
use winit::platform::android::{EventLoopBuilderExtAndroid, activity::AndroidApp};
|
||||
|
||||
use crate::emulator::{
|
||||
misc::rpc::RpcClient,
|
||||
system::{
|
||||
emulator::run_emulator,
|
||||
memory::MainStore,
|
||||
model::{Command, State},
|
||||
processor::Processor,
|
||||
},
|
||||
ui::{
|
||||
control_unit::ControlPanel, display::Display, editor::Editor,
|
||||
interface::EmulatorUI, memory_inspector::MemoryInspector,
|
||||
stack_inspector::StackInspector,
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn android_main(app: AndroidApp) -> Result<(), Box<dyn std::error::Error>> {
|
||||
use crate::emulator::{config::Config, misc::rpc::get_rpc_client_or_none};
|
||||
use std::path::Path;
|
||||
|
||||
// Initialize channels and read in configuration.
|
||||
let (cmd_sender, cmd_receiver) = std::sync::mpsc::channel();
|
||||
let (state_sender, state_reciever) = std::sync::mpsc::channel();
|
||||
let config = Config::load(Path::new(".dsa.emulator.toml"))?;
|
||||
|
||||
// Setup RPC if enabled.
|
||||
let (rpc_sender, rpc_reciever) = std::sync::mpsc::channel();
|
||||
|
||||
let rpc_client =
|
||||
get_rpc_client_or_none(&config, rpc_sender, rpc_reciever)?.map(Arc::new);
|
||||
|
||||
setup_emulator(cmd_receiver, state_sender, rpc_client);
|
||||
|
||||
let ui = setup_ui(cmd_sender, state_reciever);
|
||||
|
||||
// Run UI.
|
||||
#[allow(unused_variables)]
|
||||
let options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default().with_inner_size([800.0, 600.0]),
|
||||
event_loop_builder: Some(Box::new(move |builder| {
|
||||
#[cfg(target_os = "android")]
|
||||
builder.with_android_app(app);
|
||||
})),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
"DSA Simulator (Damn Simple Architecture 🔥)",
|
||||
options,
|
||||
Box::new(move |cc| {
|
||||
cc.egui_ctx.set_visuals(egui::Visuals::default());
|
||||
Ok(Box::new(ui))
|
||||
}),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn setup_emulator(
|
||||
cmd_receiver: Receiver<Command>,
|
||||
state_sender: Sender<State>,
|
||||
rpc_client: Option<Arc<RpcClient>>,
|
||||
) {
|
||||
let main_store = MainStore::new();
|
||||
let processor = Processor::new(Box::new(main_store), vec![]);
|
||||
|
||||
thread::spawn(move || {
|
||||
run_emulator(&cmd_receiver, &state_sender, processor, rpc_client.as_ref());
|
||||
});
|
||||
}
|
||||
|
||||
/// Creates the [`EmulatorUI`].
|
||||
#[must_use]
|
||||
pub fn setup_ui(
|
||||
cmd_sender: Sender<Command>,
|
||||
state_reciever: Receiver<State>,
|
||||
) -> EmulatorUI {
|
||||
let mut ui = EmulatorUI::new(cmd_sender.clone(), state_reciever);
|
||||
|
||||
// Create UI modules.
|
||||
let control_unit = ControlPanel::new(cmd_sender.clone());
|
||||
|
||||
ui.add_component(Box::new(control_unit));
|
||||
|
||||
let mem_inspector = MemoryInspector::new(cmd_sender.clone());
|
||||
ui.add_component(Box::new(mem_inspector));
|
||||
|
||||
let stack_inspector = StackInspector::new();
|
||||
ui.add_component(Box::new(stack_inspector));
|
||||
|
||||
let editor = Editor::new(cmd_sender);
|
||||
ui.add_component(Box::new(editor));
|
||||
|
||||
let display = Display::new();
|
||||
ui.add_component(Box::new(display));
|
||||
|
||||
let history = emulator::ui::history::History::new();
|
||||
ui.add_component(Box::new(history));
|
||||
|
||||
ui
|
||||
}
|
||||
|
||||
+4
-107
@@ -1,26 +1,7 @@
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
path::Path,
|
||||
sync::mpsc::{Receiver, Sender},
|
||||
thread,
|
||||
};
|
||||
|
||||
use dsa_rs::emulator::misc::rpc::{RpcClient, get_rpc_client_or_none};
|
||||
|
||||
use dsa_rs::emulator::{
|
||||
config::Config,
|
||||
system::{
|
||||
emulator::run_emulator,
|
||||
memory::MainStore,
|
||||
model::{Command, State},
|
||||
processor::Processor,
|
||||
},
|
||||
ui::{
|
||||
control_unit::ControlPanel, display::Display, editor::Editor,
|
||||
interface::EmulatorUI, memory_inspector::MemoryInspector,
|
||||
stack_inspector::StackInspector,
|
||||
},
|
||||
};
|
||||
use dsa_rs::emulator::{config::Config, misc::rpc::get_rpc_client_or_none};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Initialize channels and read in configuration.
|
||||
@@ -34,9 +15,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let rpc_client =
|
||||
get_rpc_client_or_none(&config, rpc_sender, rpc_reciever)?.map(Arc::new);
|
||||
|
||||
setup_emulator(cmd_receiver, state_sender, rpc_client);
|
||||
dsa_rs::setup_emulator(cmd_receiver, state_sender, rpc_client);
|
||||
|
||||
let ui = setup_ui(cmd_sender, state_reciever);
|
||||
let ui = dsa_rs::setup_ui(cmd_sender, state_reciever);
|
||||
|
||||
// Run UI.
|
||||
#[allow(unused_variables)]
|
||||
@@ -56,87 +37,3 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_emulator(
|
||||
cmd_receiver: Receiver<Command>,
|
||||
state_sender: Sender<State>,
|
||||
rpc_client: Option<Arc<RpcClient>>,
|
||||
) {
|
||||
let main_store = MainStore::new();
|
||||
let processor = Processor::new(Box::new(main_store), vec![]);
|
||||
|
||||
thread::spawn(move || {
|
||||
run_emulator(&cmd_receiver, &state_sender, processor, rpc_client.as_ref());
|
||||
});
|
||||
}
|
||||
|
||||
/// Creates the [`EmulatorUI`].
|
||||
fn setup_ui(cmd_sender: Sender<Command>, state_reciever: Receiver<State>) -> EmulatorUI {
|
||||
let mut ui = EmulatorUI::new(cmd_sender.clone(), state_reciever);
|
||||
|
||||
// Create UI modules.
|
||||
let control_unit = ControlPanel::new(cmd_sender.clone());
|
||||
|
||||
ui.add_component(Box::new(control_unit));
|
||||
|
||||
let mem_inspector = MemoryInspector::new(cmd_sender.clone());
|
||||
ui.add_component(Box::new(mem_inspector));
|
||||
|
||||
let stack_inspector = StackInspector::new();
|
||||
ui.add_component(Box::new(stack_inspector));
|
||||
|
||||
let editor = Editor::new(cmd_sender.clone());
|
||||
ui.add_component(Box::new(editor));
|
||||
|
||||
let display = Display::new();
|
||||
ui.add_component(Box::new(display));
|
||||
|
||||
let history = dsa_rs::emulator::ui::history::History::new();
|
||||
ui.add_component(Box::new(history));
|
||||
|
||||
ui
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
use winit::platform::android::{EventLoopBuilderExtAndroid, activity::AndroidApp};
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[unsafe(no_mangle)]
|
||||
fn android_main(app: AndroidApp) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Initialize channels and read in configuration.
|
||||
let (cmd_sender, cmd_receiver) = std::sync::mpsc::channel();
|
||||
let (state_sender, state_reciever) = std::sync::mpsc::channel();
|
||||
let config = Config::load(Path::new(".dsa.emulator.toml"))?;
|
||||
|
||||
// Setup RPC if enabled.
|
||||
let (rpc_sender, rpc_reciever) = std::sync::mpsc::channel();
|
||||
|
||||
let rpc_client =
|
||||
get_rpc_client_or_none(&config, rpc_sender, rpc_reciever)?.map(Arc::new);
|
||||
|
||||
setup_emulator(cmd_receiver, state_sender, rpc_client);
|
||||
|
||||
let ui = setup_ui(cmd_sender, state_reciever);
|
||||
|
||||
// Run UI.
|
||||
#[allow(unused_variables)]
|
||||
let options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default().with_inner_size([800.0, 600.0]),
|
||||
event_loop_builder: Some(Box::new(move |builder| {
|
||||
#[cfg(target_os = "android")]
|
||||
builder.with_android_app(app);
|
||||
})),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
"DSA Simulator (Damn Simple Architecture 🔥)",
|
||||
options,
|
||||
Box::new(move |cc| {
|
||||
cc.egui_ctx.set_visuals(egui::Visuals::default());
|
||||
Ok(Box::new(ui))
|
||||
}),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml-model href="http://schemas.android.com/apk/res/android"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.dsa.emulator">
|
||||
package="com.dsa.emulator"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
|
||||
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="35" />
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
<!-- <uses-permission android:name="android.permission.INTERNET" /> -->
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:label="DSA Emulator"
|
||||
android:hasCode="false">
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:hasCode="false"
|
||||
android:hardwareAccelerated="true">
|
||||
<activity
|
||||
android:name="android.app.NativeActivity"
|
||||
android:label="DSA Emulator"
|
||||
android:exported="true">
|
||||
android:exported="true"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:screenOrientation="unspecified"
|
||||
android:launchMode="singleInstance">
|
||||
<meta-data
|
||||
android:name="android.app.lib_name"
|
||||
android:value="dsa_rs" />
|
||||
@@ -21,4 +32,4 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
</manifest>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
$env:ANDROID_HOME = "C:\Users\jacob\AppData\Local\Android\Sdk"
|
||||
$TOOL_PREFIX = "$env:ANDROID_HOME\build-tools\35.0.1"
|
||||
|
||||
# Only really works on Windows, for aarch64.
|
||||
|
||||
# Create directories
|
||||
New-Item -ItemType Directory -Force -Path "..\target\apk_build\lib\arm64-v8a"
|
||||
New-Item -ItemType Directory -Force -Path "..\target\apk_build\res\values"
|
||||
New-Item -ItemType Directory -Force -Path "..\target\apk_build\res\mipmap-hdpi"
|
||||
New-Item -ItemType Directory -Force -Path "..\target\apk_build\res\mipmap-mdpi"
|
||||
New-Item -ItemType Directory -Force -Path "..\target\apk_build\res\mipmap-xhdpi"
|
||||
New-Item -ItemType Directory -Force -Path "..\target\apk_build\res\mipmap-xxhdpi"
|
||||
|
||||
# Copy the shared library
|
||||
Copy-Item "..\target\aarch64-linux-android\release\libdsa_rs.so" "..\target\apk_build\lib\arm64-v8a\"
|
||||
|
||||
# Copy the manifest
|
||||
Copy-Item "..\resources\emulator\AndroidManifest.xml" "..\target\apk_build\AndroidManifest.xml"
|
||||
|
||||
# Copy the icons
|
||||
Copy-Item "..\resources\emulator\AppIcon.png" "..\target\apk_build\res\mipmap-hdpi\ic_launcher.png"
|
||||
Copy-Item "..\resources\emulator\AppIcon.png" "..\target\apk_build\res\mipmap-mdpi\ic_launcher.png"
|
||||
Copy-Item "..\resources\emulator\AppIcon.png" "..\target\apk_build\res\mipmap-xhdpi\ic_launcher.png"
|
||||
Copy-Item "..\resources\emulator\AppIcon.png" "..\target\apk_build\res\mipmap-xxhdpi\ic_launcher.png"
|
||||
|
||||
# Create strings.xml
|
||||
@"
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">DSA Emulator</string>
|
||||
</resources>
|
||||
"@ | Out-File -FilePath "..\target\apk_build\res\values\strings.xml" -Encoding utf8
|
||||
|
||||
# Change to build directory
|
||||
Push-Location "..\target\apk_build"
|
||||
|
||||
try {
|
||||
# Compile resources
|
||||
& "$TOOL_PREFIX\aapt2.exe" compile --dir res -o compiled_resources.zip
|
||||
|
||||
# Link resources
|
||||
& "$TOOL_PREFIX\aapt2.exe" link -o unaligned.apk `
|
||||
-I "$env:ANDROID_HOME\platforms\android-35\android.jar" `
|
||||
--manifest AndroidManifest.xml `
|
||||
compiled_resources.zip
|
||||
|
||||
# Add native libraries to APK
|
||||
& "C:\Program Files\7-Zip\7z.exe" a -tzip unaligned.apk lib\*
|
||||
|
||||
# Align APK
|
||||
& "$TOOL_PREFIX\zipalign.exe" -v 4 unaligned.apk aligned.apk
|
||||
|
||||
# Generate debug keystore if it doesn't exist
|
||||
if (-not (Test-Path "debug.keystore")) {
|
||||
& keytool -genkey -v -keystore debug.keystore -alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 -storepass android -keypass android -dname "CN=Android Debug,O=Android,C=US"
|
||||
}
|
||||
|
||||
# Sign APK
|
||||
& "$TOOL_PREFIX\apksigner.bat" sign --ks debug.keystore --ks-key-alias androiddebugkey --ks-pass pass:android --key-pass pass:android --out dsa_emulator.apk aligned.apk
|
||||
|
||||
# Copy final APK
|
||||
Copy-Item "dsa_emulator.apk" "..\dsa_emulator.apk"
|
||||
|
||||
Write-Host "APK created successfully at: ..\target\dsa_emulator.apk" -ForegroundColor Green
|
||||
}
|
||||
catch {
|
||||
Write-Error "Build failed: $_"
|
||||
}
|
||||
finally {
|
||||
# Return to original directory
|
||||
Pop-Location
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
|
||||
export ANDROID_HOME="/mnt/c/Users/jacob/AppData/Local/Android/Sdk"
|
||||
export TOOL_PREFIX="$ANDROID_HOME/build-tools/35.0.1"
|
||||
|
||||
# Only really works on Linux, for aarch64.
|
||||
|
||||
mkdir -p ../target/apk_build/lib/arm64-v8a
|
||||
mkdir -p ../target/apk_build/res/values
|
||||
mkdir -p ../target/apk_build/res/mipmap-hdpi
|
||||
mkdir -p ../target/apk_build/res/mipmap-mdpi
|
||||
mkdir -p ../target/apk_build/res/mipmap-xhdpi
|
||||
mkdir -p ../target/apk_build/res/mipmap-xxhdpi
|
||||
|
||||
# Copy the shared library.
|
||||
cp ../target/aarch64-linux-android/release/libdsa_rs.so ../target/apk_build/lib/arm64-v8a/
|
||||
|
||||
# Copy the manifest.
|
||||
cp AndroidManifest.xml ../target/apk_build/AndroidManifest.xml
|
||||
|
||||
cat << EOF > ../target/apk_build/res/values/strings.xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">DSA Emulator</string>
|
||||
</resources>
|
||||
EOF
|
||||
|
||||
pushd ../target/apk_build
|
||||
|
||||
$TOOL_PREFIX/aapt2 compile --dir res -o compiled_resources.zip
|
||||
$TOOL_PREFIX/aapt2 link -o unaligned.apk \
|
||||
-I "$ANDROID_HOME/platforms/android-35/android.jar" \
|
||||
--manifest AndroidManifest.xml \
|
||||
compiled_resources.zip
|
||||
|
||||
zip -r unaligned.apk lib/
|
||||
|
||||
$TOOL_PREFIX/zipalign -v 4 unaligned.apk aligned.apk
|
||||
|
||||
keytool -genkey -v -keystore debug.keystore -alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 -storepass android -keypass android -dname "CN=Android Debug,O=Android,C=US"
|
||||
|
||||
$TOOL_PREFIX/apksigner sign --ks debug.keystore --ks-key-alias androiddebugkey --ks-pass pass:android --key-pass pass:android --out dsa_emulator.apk aligned.apk
|
||||
|
||||
cp dsa_emulator.apk ../dsa_emulator.apk
|
||||
|
||||
popd
|
||||
Reference in New Issue
Block a user