initial commit

This commit is contained in:
xoureldeen 2024-08-29 01:04:08 +03:00
parent 250d795823
commit 48648e4ab5
10 changed files with 201 additions and 169 deletions

View file

@ -106,7 +106,7 @@ public class MainActivity extends AppCompatActivity {
private AdRequest adRequest;
public DrawerLayout mainDrawer;
private String TAG = "MainActivity";
public static /**/ LinearLayout extVncLayout;
public static /**/ LinearLayout extViewerLayout;
public static AppBarLayout appbar;
public TextView totalRam;
public TextView usedRam;
@ -135,10 +135,16 @@ public class MainActivity extends AppCompatActivity {
appbar = findViewById(R.id.appbar);
appbar.setExpanded(false);
extVncLayout = findViewById(R.id.extVnc);
extViewerLayout = findViewById(R.id.extVnc);
TextView extTitle = findViewById(R.id.extTitle);
TextView tvLogin = findViewById(R.id.tvLogin);
tvLogin.setText("LOGIN --> " + Config.defaultVNCHost + ":" + (5900 + Config.defaultVNCPort)/* + "\nPASSWORD --> " + Config.defaultVNCPasswd*/);
if (MainSettingsManager.getVmUi(activity).equals("VNC")) {
tvLogin.setText("LOGIN --> " + Config.defaultVNCHost + ":" + (5900 + Config.defaultVNCPort)/* + "\nPASSWORD --> " + Config.defaultVNCPasswd*/);
} else {
extTitle.setText("EXTERNAL X11");
tvLogin.setText("Now Open Termux X11");
}
Button stopBtn = findViewById(R.id.stopBtn);
stopBtn.setOnClickListener(new View.OnClickListener() {
@ -150,7 +156,7 @@ public class MainActivity extends AppCompatActivity {
Terminal vterm = new Terminal(activity);
vterm.executeShellCommand("killall qemu-system-*", false, activity);
extVncLayout.setVisibility(View.GONE);
extViewerLayout.setVisibility(View.GONE);
appbar.setExpanded(false);
}
});
@ -774,7 +780,7 @@ public class MainActivity extends AppCompatActivity {
if (MainSettingsManager.getVmUi(activity).equals("VNC")) {
if (MainSettingsManager.getVncExternal(MainActivity.activity)) {
extVncLayout.setVisibility(View.VISIBLE);
extViewerLayout.setVisibility(View.VISIBLE);
appbar.setExpanded(true);
progressDialog.dismiss();
} else {
@ -791,11 +797,10 @@ public class MainActivity extends AppCompatActivity {
} else if (MainSettingsManager.getVmUi(activity).equals("SPICE")) {
//activity.startActivity(new Intent(activity, RemoteCanvasActivity.class));
} else if (MainSettingsManager.getVmUi(activity).equals("X11")) {
try {
TermuxX11.main(new String[]{":0"});
} catch (ErrnoException e) {
throw new RuntimeException(e);
}
extViewerLayout.setVisibility(View.VISIBLE);
appbar.setExpanded(true);
progressDialog.dismiss();
Intent x11Intent = new Intent();
x11Intent.setClassName("com.termux.x11", "com.termux.x11.MainActivity");
@ -806,6 +811,12 @@ public class MainActivity extends AppCompatActivity {
} catch (ActivityNotFoundException e) {
Log.e("LaunchActivity", "Activity not found: " + e.getMessage());
}
try {
TermuxX11.main(new String[]{":0"});
} catch (ErrnoException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -6,8 +6,10 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;
import androidx.core.app.NotificationCompat;
@ -26,6 +28,9 @@ public class MainService extends Service {
private String TAG = "MainService";
public static MainService service;
private PowerManager.WakeLock wakeLock;
private WifiManager.WifiLock wifiLock;
@Override
public void onCreate() {
super.onCreate();
@ -44,11 +49,19 @@ public class MainService extends Service {
.addAction(R.drawable.round_logout_24, "Stop", pStopSelf)
.build();
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Vectras::MyWakeLockTag");
wakeLock.acquire();
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "Vectras::MyWifiLockTag");
wifiLock.acquire();
if (env != null) {
if (service != null) {
String filesDir = MainActivity.activity.getFilesDir().getAbsolutePath();
Terminal vterm = new Terminal(this);
//vterm.executeShellCommand("chmod 770 /run/pulse -R");
vterm.executeShellCommand("awesome &", false, MainActivity.activity);
//vterm.executeShellCommand("pulseaudio --system --disallow-exit --disallow-module-loading --daemonize --log-level=debug --log-time=1");
vterm.executeShellCommand(env, true, MainActivity.activity);
}
@ -89,6 +102,21 @@ public class MainService extends Service {
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
// Release the WakeLock if it is held
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
}
// Release the WifiLock if it is held
if (wifiLock != null && wifiLock.isHeld()) {
wifiLock.release();
}
}
@Override
public IBinder onBind(Intent intent) {
return null;

View file

@ -1,6 +1,9 @@
package com.vectras.vm;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.content.Intent.ACTION_OPEN_DOCUMENT;
import static android.os.Build.VERSION.SDK_INT;
import static com.vectras.vm.utils.UIUtils.UIAlert;
@ -10,20 +13,26 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.PowerManager;
import android.provider.DocumentsContract;
import android.provider.Settings;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import com.google.android.material.button.MaterialButton;
@ -66,6 +75,9 @@ public class SetupQemuActivity extends AppCompatActivity implements View.OnClick
tarPath = getExternalFilesDir("data") + "/data.tar.gz";
if (!checkPermission())
requestPermission();
alertDialog = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create();
alertDialog.setTitle("BOOTSTRAP REQUIRED!");
alertDialog.setMessage("U can choose between auto download and setup or manual setup by choosing bootstrap file.");
@ -97,9 +109,53 @@ public class SetupQemuActivity extends AppCompatActivity implements View.OnClick
setupVectras();
} else {
alertDialog.show();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm != null && !pm.isIgnoringBatteryOptimizations(getPackageName())) {
showDisableBatteryOptimizationDialog();
}
}
}
public static String[] storage_permissions = {
WRITE_EXTERNAL_STORAGE,
READ_EXTERNAL_STORAGE
};
private boolean checkPermission() {
if (SDK_INT >= Build.VERSION_CODES.R) {
return Environment.isExternalStorageManager();
} else {
int result = ContextCompat.checkSelfPermission(this, READ_EXTERNAL_STORAGE);
int result1 = ContextCompat.checkSelfPermission(this, WRITE_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
}
}
private void requestPermission() {
ActivityCompat.requestPermissions(this,
permissions(),
1002);
}
public static String[] permissions() {
String[] p;
p = storage_permissions;
return p;
}
private void showDisableBatteryOptimizationDialog() {
new AlertDialog.Builder(this)
.setTitle("Disable Battery Optimization")
.setMessage("To ensure the app functions correctly, please disable battery optimization for this app.")
.setCancelable(false)
.setPositiveButton("Disable", (dialog, which) -> {
Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
startActivity(intent);
})
.show();
}
public void onClick(View v) {
int id = v.getId();
if (id == R.id.btnInstall) {
@ -352,7 +408,7 @@ public class SetupQemuActivity extends AppCompatActivity implements View.OnClick
" apk update;" +
" apk add tar libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +
" libusbredirparser usbredir-dev libiscsi-dev sdl2 sdl2-dev libepoxy-dev virglrenderer-dev rdma-core" +
" libusb ncurses-libs curl libnfs sdl2 gtk+3.0 fuse libpulse libseccomp jack pipewire liburing xkeyboard-config;" +
" libusb ncurses-libs curl libnfs sdl2 gtk+3.0 fuse libpulse libseccomp jack pipewire liburing awesome lxterminal font-terminus xkeyboard-config;" +
" tar -xzvf " + tarPath + " -C /;" +
" rm " + tarPath + ";" +
" mkdir -p ~/.vnc && echo -e \"555555\\n555555\" | vncpasswd -f > ~/.vnc/passwd && chmod 0600 ~/.vnc/passwd;" +
@ -371,7 +427,7 @@ public class SetupQemuActivity extends AppCompatActivity implements View.OnClick
File selectedFilePath = new File(getPath(content_describer));
ProgressBar loading = progressBar;
String abi = Build.SUPPORTED_ABIS[0];
if (selectedFilePath.toString().endsWith(abi+".tar.gz")) {
if (selectedFilePath.toString().endsWith(abi + ".tar.gz")) {
loading.setVisibility(View.VISIBLE);
new Thread(new Runnable() {
@Override
@ -423,6 +479,14 @@ public class SetupQemuActivity extends AppCompatActivity implements View.OnClick
alertDialog.show();
UIAlert(activity, "INVALID FILE", "please select vectras-vm-" + abi + ".tar.gz file");
}
} else if (requestCode == 1002 && resultCode == RESULT_OK) {
if (!checkPermission()) {
requestPermission();
Toast.makeText(this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
}
} else
alertDialog.show();
}

View file

@ -57,7 +57,7 @@ public class SplashActivity extends AppCompatActivity implements Runnable {
SharedPreferences prefs = getSharedPreferences(CREDENTIAL_SHARED_PREF, Context.MODE_PRIVATE);
try {
new Handler().postDelayed(activity, 3000);
new Handler().postDelayed(activity, 1000);
} catch (Exception e) {
throw new RuntimeException(e);
}/*
@ -67,8 +67,6 @@ public class SplashActivity extends AppCompatActivity implements Runnable {
} else {
}
*/
if (!checkPermission())
requestPermission();
MainSettingsManager.setOrientationSetting(activity, 1);
setupFiles();

View file

@ -25,8 +25,6 @@ public class StartVM {
ArrayList<String> params = new ArrayList<>(Arrays.asList(qemu));
params.add("awesome;");
if (MainSettingsManager.getArch(activity).equals("I386"))
params.add("qemu-system-i386");
else if (MainSettingsManager.getArch(activity).equals("X86_64"))

View file

@ -24,178 +24,107 @@ import com.vectras.qemu.MainSettingsManager;
import com.vectras.qemu.MainVNCActivity;
import com.vectras.vm.MainActivity;
import com.vectras.vm.R;
import com.vectras.vm.VectrasApp;
public class Terminal {
private static final String TAG = "Vterm";
private Context context;
private String user = "root";
public static Process qemuProcess;
private Process qemuProcess;
private BufferedWriter commandWriter;
public static String DISPLAY = ":0";
public Terminal(Context context) {
this.context = context;
startQemuProcess();
}
private String getLocalIpAddress() {
private void startQemuProcess() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && inetAddress.getHostAddress().toString().contains(".")) {
return inetAddress.getHostAddress().toString();
ProcessBuilder processBuilder = new ProcessBuilder();
String filesDir = context.getFilesDir().getAbsolutePath();
String nativeLibDir = context.getApplicationInfo().nativeLibraryDir;
File tmpDir = new File(context.getFilesDir(), "tmp");
processBuilder.environment().put("PROOT_TMP_DIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("PROOT_LOADER", nativeLibDir + "/libproot-loader.so");
processBuilder.environment().put("PROOT_LOADER_32", nativeLibDir + "/libproot-loader32.so");
processBuilder.environment().put("HOME", "/root");
processBuilder.environment().put("USER", user);
processBuilder.environment().put("PATH", "/bin:/usr/bin:/sbin:/usr/sbin");
processBuilder.environment().put("TERM", "xterm-256color");
processBuilder.environment().put("TMPDIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("SHELL", "/bin/sh");
processBuilder.environment().put("DISPLAY", DISPLAY);
String[] prootCommand = {
nativeLibDir + "/libproot.so",
"--kill-on-exit",
"--link2symlink",
"-0",
"-r", filesDir + "/distro",
"-b", "/dev",
"-b", "/proc",
"-b", "/sys",
"-b", "/sdcard",
"-b", "/storage",
"-b", "/data",
"-b", filesDir + "/distro/root:/dev/shm",
"-b", tmpDir.getAbsolutePath() + ":/tmp",
"-w", "/root",
"/usr/bin/env", "-i",
"HOME=/root",
"DISPLAY=" + DISPLAY,
"/bin/sh",
"--login"
};
processBuilder.command(prootCommand);
qemuProcess = processBuilder.start();
commandWriter = new BufferedWriter(new OutputStreamWriter(qemuProcess.getOutputStream()));
// Thread to read the output from the process
new Thread(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(qemuProcess.getInputStream()));
BufferedReader errorReader = new BufferedReader(new InputStreamReader(qemuProcess.getErrorStream()))) {
String line;
while ((line = reader.readLine()) != null) {
Log.d(TAG, line);
com.vectras.vm.logger.VectrasStatus.logError("<font color='yellow'>VTERM: >" + line + "</font>");
}
while ((line = errorReader.readLine()) != null) {
Log.w(TAG, line);
com.vectras.vm.logger.VectrasStatus.logError("<font color='red'>VTERM ERROR: >" + line + "</font>");
}
} catch (IOException e) {
Log.e(TAG, "Error reading from qemuProcess", e);
}
}
} catch (SocketException ex) {
ex.printStackTrace();
}).start();
} catch (IOException e) {
Log.e(TAG, "Failed to start qemuProcess", e);
}
return null;
}
private void showDialog(String message, Activity activity) {
AlertDialog dialog = new AlertDialog.Builder(activity, R.style.MainDialogTheme)
.setTitle("Execution Result")
.setMessage(message)
.setPositiveButton("OK", (dialogInterface, i) -> dialogInterface.dismiss())
.create();
dialog.show();
}
// Method to execute the shell command
public void executeShellCommand(String userCommand, boolean showResultDialog, Activity dialogActivity) {
StringBuilder output = new StringBuilder();
StringBuilder errors = new StringBuilder();
Log.d(TAG, userCommand);
com.vectras.vm.logger.VectrasStatus.logError("<font color='yellow'>VTERM: >" + userCommand + "</font>");
new Thread(() -> {
try {
// Setup the qemuProcess builder to start PRoot with environmental variables and commands
ProcessBuilder processBuilder = new ProcessBuilder();
// Adjust these environment variables as necessary for your app
String filesDir = context.getFilesDir().getAbsolutePath();
String nativeLibDir = context.getApplicationInfo().nativeLibraryDir;
File tmpDir = new File(context.getFilesDir(), "tmp");
// Setup environment for the PRoot qemuProcess
processBuilder.environment().put("PROOT_TMP_DIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("PROOT_LOADER", nativeLibDir + "/libproot-loader.so");
processBuilder.environment().put("PROOT_LOADER_32", nativeLibDir + "/libproot-loader32.so");
processBuilder.environment().put("HOME", "/root");
processBuilder.environment().put("USER", user);
processBuilder.environment().put("PATH", "/bin:/usr/bin:/sbin:/usr/sbin");
processBuilder.environment().put("TERM", "xterm-256color");
processBuilder.environment().put("TMPDIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("SHELL", "/bin/sh");
processBuilder.environment().put("DISPLAY", DISPLAY);
String[] prootCommand = {
nativeLibDir + "/libproot.so", // PRoot binary path
"--kill-on-exit",
"--link2symlink",
"-0",
"-r", filesDir + "/distro", // Path to the rootfs
"-b", "/dev",
"-b", "/proc",
"-b", "/sys",
"-b", "/sdcard",
"-b", "/storage",
"-b", "/data",
"-w", "/root",
"/usr/bin/env", "-i",
"HOME=/root",
"DISPLAY="+DISPLAY,
"/bin/sh",
"--login"// The shell to execute inside PRoot
};
processBuilder.command(prootCommand);
qemuProcess = processBuilder.start();
// Get the input and output streams of the qemuProcess
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(qemuProcess.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(qemuProcess.getInputStream()));
BufferedReader errorReader = new BufferedReader(new InputStreamReader(qemuProcess.getErrorStream()));
// Send user command to PRoot
writer.write(userCommand);
writer.newLine();
writer.flush();
writer.close();
// Read the input stream for the output of the command
String line;
while ((line = reader.readLine()) != null) {
Log.d(TAG, line);
com.vectras.vm.logger.VectrasStatus.logError("<font color='yellow'>VTERM: >" + line + "</font>");
output.append(line).append("\n");
if (commandWriter != null) {
commandWriter.write(userCommand);
commandWriter.newLine();
commandWriter.flush();
}
// Read any errors from the error stream
while ((line = errorReader.readLine()) != null) {
Log.w(TAG, line);
com.vectras.vm.logger.VectrasStatus.logError("<font color='red'>VTERM ERROR: >" + line + "</font>");
output.append(line).append("\n");
}
// Clean up
reader.close();
errorReader.close();
int exitCode = qemuProcess.waitFor(); // Wait for the process to finish
if (exitCode == 0) {
output.append("Execution finished successfully.\n");
output.append(reader.readLine()).append("\n");
Log.i(TAG, reader.readLine());
} else {
output.append("Execution finished with exit code: ").append(exitCode).append("\n");
output.append(reader.readLine()).append("\n");
Log.i(TAG, reader.readLine());
}
} catch (IOException | InterruptedException e) {
output.append(e.getMessage());
errors.append(Log.getStackTraceString(e));
MainActivity.clearNotifications();
} finally {
// Switch to main thread after execution
new Handler(Looper.getMainLooper()).post(() -> {
// If showResultDialog is enabled, show the dialog with the result or errors
if (showResultDialog) {
String finalOutput = output.toString();
String finalErrors = errors.toString();
// bcuz there is dumb users bruh
showDialog(finalOutput.isEmpty() ? finalErrors : finalOutput.replace("read interrupted", "Done!"), dialogActivity);
}
});
} catch (IOException e) {
Log.e(TAG, "Error writing to qemuProcess", e);
}
}).start();
}
private boolean checkInstallation() {
String filesDir = context.getFilesDir().getAbsolutePath();
File distro = new File(filesDir, "distro");
return distro.exists();
}
public static void killQemuProcess() {
if (qemuProcess != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
qemuProcess.destroyForcibly();
else
qemuProcess.destroy();
if (!MainSettingsManager.getVncExternal(MainActivity.activity)) {
MainVNCActivity.activity.finish();
MainVNCActivity.started = false;
}
qemuProcess = null; // Set it to null after destroying it
Log.d(TAG, "QEMU process destroyed.");
} else {
Log.d(TAG, "QEMU process was null.");
}
}
}