V2.1 stable
This commit is contained in:
Epic Studios 2024-01-10 04:46:21 +02:00
parent df34043cfe
commit 512140534c
450 changed files with 64666 additions and 0 deletions

View file

@ -0,0 +1,185 @@
/*
Copyright (C) Max Kastanas 2012
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.vectras.qemu;
import android.androidVNC.COLORMODEL;
import android.androidVNC.VncCanvasActivity;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Environment;
import android.widget.ImageView.ScaleType;
import com.vectras.vm.AppConfig;
import java.util.Hashtable;
import java.util.LinkedHashMap;
/**
*
* @author dev
*/
public class Config {
// Constants
public static final int UI_VNC = 0;
public static final int UI_SDL = 1;
public static final int UI_SPICE = 2;
public static final int SDL_MOUSE_LEFT = 1;
public static final int SDL_MOUSE_MIDDLE = 2;
public static final int SDL_MOUSE_RIGHT = 3;
public static final int VNC_REQUEST_CODE = 1004;
public static final int VNC_RESET_RESULT_CODE = 1006;
public static final int SDL_REQUEST_CODE = 1007;
public static final String ACTION_START = "com.vectras.qemu.action.STARTVM";
// GUI Options
public static final boolean enable_SDL = true;
public static final boolean enable_SPICE = false;
public static final boolean enable_qemu_fullScreen = true;
// App config
public static final String APP_NAME = "Vectras Emulator";
public static String storagedir = null;
//Some OSes don't like emulated multi cores for QEMU 2.9.1 you can disable here
/// thought there is also the Disable TSC feature so you don't have to do it here
public static boolean enableSMPOnlyOnKVM = false;
//set to true if you need to debug native library loading
public static boolean loadNativeLibsEarly = false;
//XXX: QEMU 3.1.0 needs the libraries to be loaded from the main thread
public static boolean loadNativeLibsMainThread = true;
public static String wakeLockTag = "vectras:wakelock";
public static String wifiLockTag = "vectras:wifilock";
//this will be populated later
public static String cacheDir = null;
//we disable mouse modes for now
public static boolean disableMouseModes = true;
//double tap an hold is still buggy so we keep using the old-way trackpad
public static boolean enableDragOnLongPress = true;
//we need to define the configuration for the VNC client since we replaced some deprecated
// functions
public static Bitmap.Config bitmapConfig = Bitmap.Config.RGB_565;
//XXX set scaling to linear it's a tad slower but it's worth it
public static int SDLHintScale=1;
public static boolean viewLogInternally = true;
//XXX some archs don't support floppy or sd card
public static boolean enableEmulatedFloppy = true;
public static boolean enableEmulatedSDCard;
public static String destLogFilename = "vectraslog.txt";
public static String notificationChannelID = "vectras";
public static String notificationChannelName = "vectras";
public static boolean showToast = false;
public static boolean closeFileDescriptors = true;
public static String hda_path;
public static String extra_params;
public static final String getCacheDir(){
return cacheDir.toString();
}
public static final String getBasefileDir() {
return getCacheDir() + "/vectras/";
}
public static String getTmpFolder() {
return getBasefileDir() + "var/tmp"; // Do not modify
}
public static String machineFolder = "machines/";
public static String getMachineDir(){
return getBasefileDir() + machineFolder;
}
public static String logFilePath = null;
public static final String defaultDNSServer = "8.8.8.8";
public static String state_filename = "vm.state";
//QMP
public static String QMPServer = "127.0.0.1";
public static int QMPPort = 4444;
public static int MAX_DISPLAY_REFRESH_RATE = 100; //Hz
// VNC Defaults
public static String defaultVNCHost = "127.0.0.1";
public static final String defaultVNCUsername = "vectras";
public static final String defaultVNCPasswd = "";
//It seems that for new veersion of qemu it expectes a relative number
// so we stop using absolute port numbers
public static final int defaultVNCPort = 1;
public static final String defaultVNCColorMode = COLORMODEL.C24bit.nameString();
public static final ScaleType defaultFullscreenScaleMode = ScaleType.FIT_CENTER;
public static final ScaleType defaultScaleModeCenter = ScaleType.CENTER;
public static final String defaultInputMode = VncCanvasActivity.TOUCH_ZOOM_MODE;
//Keyboard Layout
public static String defaultKeyboardLayout = "en-us";
public static boolean enableToggleKeyboard = false;
// Debug
public static final boolean debug = false;
public static boolean debugQmp = false;
//remove in production
public static boolean debugStrictMode = false;
public static boolean processMouseHistoricalEvents = false;
public static String getLocalQMPSocketPath() {
return Config.getCacheDir()+"/qmpsocket";
}
public static String getLocalVNCSocketPath() {
return Config.getCacheDir()+"/vncsocket";
}
public static enum MouseMode {
Trackpad, External
}
public static MouseMode mouseMode = MouseMode.Trackpad;
//specify hd interface, alternative we don't need it right now
public static boolean enable_hd_if = false;
public static String hd_if_type = "ide";
//Change to true in prod if you want to be notified by default for new versions
public static boolean defaultCheckNewVersion = true;
public static final String sharedFolder = AppConfig.sharedFolder;
public static String machinename = "VECTRAS";
public static int paused = 0;
public static String ui = "VNC";
public static boolean maxPriority = false;
}

View file

@ -0,0 +1,676 @@
package com.vectras.qemu;
import android.androidVNC.RfbProto;
import android.androidVNC.VncCanvas;
import android.app.Activity;
import android.app.NotificationManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.StrictMode;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import com.vectras.qemu.jni.StartVM;
import com.vectras.qemu.utils.FileInstaller;
import com.vectras.qemu.utils.FileUtils;
import com.vectras.qemu.utils.Machine;
import com.vectras.qemu.utils.QmpClient;
import com.vectras.vm.R;
import com.vectras.vm.utils.UIUtils;
import java.io.File;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MainActivityCommon {
public static VMStatus currStatus = VMStatus.Ready;
public static boolean vmStarted = false;
public static StartVM vmexecutor;
public static String vnc_passwd = "vectras";
public static int vnc_allow_external = 1;
public static int qmp_allow_external = 0;
public static ProgressDialog progDialog;
public static View parent;
public static InstallerTask installerTaskTask;
public static boolean timeQuit = false;
public static Object lockTime = new Object();
public static final String TAG = "VECTRAS";
public static AppCompatActivity activity = null;
public static boolean libLoaded;
static public void onInstall(boolean force) {
FileInstaller.installFiles(activity, force);
}
public static String getVnc_passwd() {
return vnc_passwd;
}
public static void setVnc_passwd(String vnc_passwd) {
vnc_passwd = vnc_passwd;
}
public static String getLocalIpAddress() {
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();
}
}
}
} catch (SocketException ex) {
ex.printStackTrace();
}
return null;
}
// Start calling the JNI interface
public static void startvm(Activity activity, int UI) {
QmpClient.allow_external = (qmp_allow_external == 1);
vmexecutor.qmp_allow_external = qmp_allow_external;
if (UI == Config.UI_VNC) {
// disable sound card with VNC
vmexecutor.enablevnc = 1;
vmexecutor.enablespice = 0;
vmexecutor.sound_card = null;
vmexecutor.vnc_allow_external = vnc_allow_external;
RfbProto.allow_external = (vnc_allow_external == 1);
vmexecutor.vnc_passwd = vnc_passwd;
} else if (UI == Config.UI_SDL) {
vmexecutor.enablevnc = 0;
vmexecutor.enablespice = 0;
} else if (UI == Config.UI_SPICE) {
vmexecutor.vnc_allow_external = vnc_allow_external;
vmexecutor.vnc_passwd = vnc_passwd;
vmexecutor.enablevnc = 0;
vmexecutor.enablespice = 1;
}
vmexecutor.startvm(activity, UI);
}
public static void cleanup() {
vmStarted = false;
//XXX flush and close all file descriptors if we haven't already
FileUtils.close_fds();
////XXX; we wait till fds flush and close
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//set the exit code
MainSettingsManager.setExitCode(activity, 1);
//XXX: SDL seems to lock the keyboard events
// unless we finish the starting activity
activity.finish();
Log.v(TAG, "Exit");
//XXX: We exit here to force unload the native libs
System.exit(0);
}
public static void changeStatus(final VMStatus status_changed) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (status_changed == VMStatus.Running) {
vmStarted = true;
} else if (status_changed == VMStatus.Ready || status_changed == VMStatus.Stopped) {
} else if (status_changed == VMStatus.Saving) {
} else if (status_changed == VMStatus.Paused) {
}
}
});
}
public static void install(boolean force) {
progDialog = ProgressDialog.show(activity, "Please Wait", "Installing BIOS...", true);
installerTaskTask = new InstallerTask();
installerTaskTask.force = force;
installerTaskTask.execute();
}
public static void checkAndLoadLibs() {
if (Config.loadNativeLibsEarly)
if (Config.loadNativeLibsMainThread)
setupNativeLibs();
else
setupNativeLibsAsync();
}
public static void clearNotifications() {
NotificationManager notificationManager = (NotificationManager) activity.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancelAll();
}
public static void setupNativeLibsAsync() {
Thread thread = new Thread(new Runnable() {
public void run() {
setupNativeLibs();
}
});
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
}
public static void savePendingEditText() {
View currentView = activity.getCurrentFocus();
if (currentView != null && currentView instanceof EditText) {
((EditText) currentView).setFocusable(false);
}
}
public static void checkLog() {
Thread t = new Thread(new Runnable() {
public void run() {
if (MainSettingsManager.getExitCode(activity) != 1) {
MainSettingsManager.setExitCode(activity, 1);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
UIUtils.promptShowLog(activity);
}
});
}
}
});
t.start();
}
public static void setupFolders() {
Thread t = new Thread(new Runnable() {
public void run() {
Config.cacheDir = activity.getCacheDir().getAbsolutePath();
Config.storagedir = Environment.getExternalStorageDirectory().toString();
// Create Temp folder
File folder = new File(Config.getTmpFolder());
if (!folder.exists())
folder.mkdirs();
}
});
t.start();
}
//XXX: sometimes this needs to be called from the main thread otherwise
// qemu crashes when it is started later
public static void setupNativeLibs() {
if (libLoaded)
return;
//Some devices need stl loaded upfront
//System.loadLibrary("stlport_shared");
//Compatibility lib
System.loadLibrary("compat-vectras");
//Glib deps
System.loadLibrary("compat-musl");
//Glib
System.loadLibrary("glib-2.0");
//Pixman for qemu
System.loadLibrary("pixman-1");
//Spice server
if (Config.enable_SPICE) {
System.loadLibrary("crypto");
System.loadLibrary("ssl");
System.loadLibrary("spice");
}
// //Load SDL library
if (Config.enable_SDL) {
System.loadLibrary("SDL2");
}
System.loadLibrary("compat-SDL2-ext");
//Vectras needed for vmexecutor
System.loadLibrary("vectras");
loadQEMULib();
libLoaded = true;
}
public static void loadQEMULib() {
try {
System.loadLibrary("qemu-system-i386");
} catch (Error ex) {
System.loadLibrary("qemu-system-x86_64");
}
}
public static void setupStrictMode() {
if (Config.debugStrictMode) {
StrictMode.setThreadPolicy(
new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork()
//.penaltyDeath()
.penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects().penaltyLog()
// .penaltyDeath()
.build());
}
}
public static void onLicense() {
PackageInfo pInfo = null;
try {
pInfo = activity.getPackageManager().getPackageInfo(activity.getClass().getPackage().getName(), PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return;
}
final PackageInfo finalPInfo = pInfo;
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
}
// Main event function
// Retrives values from saved preferences
public static void onStartButton() {
if (MainService.isRunning) {
startvnc();
} else {
if (vmexecutor == null) {
try {
vmexecutor = new StartVM(activity);
} catch (Exception ex) {
UIUtils.toastLong(activity, "Error: " + ex);
return;
}
}
// dns
vmexecutor.dns_addr = Config.defaultDNSServer;
vmexecutor.paused = 0;
if (!vmStarted) {
UIUtils.toastShort(activity, "Starting VM");
//XXX: make sure that bios files are installed in case we ran out of space in the last
// run
FileInstaller.installFiles(activity, false);
} else {
UIUtils.toastShort(activity, "Connecting to VM");
}
if (Config.ui.equals("VNC")) {
vmexecutor.enableqmp = 1; // We enable qemu monitor
startVNC();
} else if (Config.ui.equals("SDL")) {
vmexecutor.enableqmp = 0; // We disable qemu monitor
startSDL();
} else {
vmexecutor.enableqmp = 1; // We enable qemu monitor
startSPICE();
}
}
}
public static String getLanguageCode(int index) {
// TODO: Add more languages from /assets/roms/keymaps
switch (index) {
case 0:
return "en-us";
case 1:
return "es";
case 2:
return "fr";
}
return null;
}
public static void startSDL() {
Thread tsdl = new Thread(new Runnable() {
public void run() {
startsdl();
}
});
if (Config.maxPriority)
tsdl.setPriority(Thread.MAX_PRIORITY);
tsdl.start();
}
public static void startVNC() {
VncCanvas.retries = 0;
if (!vmStarted) {
Thread tvm = new Thread(new Runnable() {
public void run() {
startvm(activity, Config.UI_VNC);
}
});
if (Config.maxPriority)
tvm.setPriority(Thread.MAX_PRIORITY);
tvm.start();
} else {
startvnc();
}
}
public static void startSPICE() {
if (!vmStarted) {
Thread tvm = new Thread(new Runnable() {
public void run() {
startvm(activity, Config.UI_SPICE);
}
});
if (Config.maxPriority)
tvm.setPriority(Thread.MAX_PRIORITY);
tvm.start();
}
}
public static void onStopButton(boolean exit) {
stopVM(exit);
}
public static void onRestartButton() {
execTimer();
Machine.resetVM(activity);
}
public static void onResumeButton() {
// TODO: This probably has no effect
Thread t = new Thread(new Runnable() {
public void run() {
resumevm();
}
});
t.start();
}
public static void toggleVisibility(View view) {
if (view.getVisibility() == View.VISIBLE) {
view.setVisibility(View.GONE);
} else if (view.getVisibility() == View.GONE || view.getVisibility() == View.INVISIBLE) {
view.setVisibility(View.VISIBLE);
}
}
public static boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
activity.moveTaskToBack(true);
return true; // return
}
return false;
}
public static void startvnc() {
// Wait till Qemu settles
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(activity.getClass().getName()).log(Level.SEVERE, null, ex);
}
if (MainSettingsManager.getVncExternal(activity)) {
} else {
connectLocally();
}
}
public static void promptConnectLocally(final Activity activity) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
final AlertDialog alertDialog;
alertDialog = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create();
alertDialog.setTitle("VNC Started");
TextView stateView = new TextView(activity);
stateView.setText("VNC Server started: " + getLocalIpAddress() + ":" + Config.defaultVNCPort + "\n"
+ "Warning: VNC Connection is Unencrypted and not secure make sure you're on a private network!\n");
stateView.setPadding(20, 20, 20, 20);
alertDialog.setView(stateView);
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
}
});
alertDialog.setButton(DialogInterface.BUTTON_NEUTRAL, "Connect Locally", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
connectLocally();
}
});
alertDialog.show();
}
}, 100);
}
public static void connectLocally() {
//UIUtils.toastShort(MainActivity.this, "Connecting to VM Display");
Intent intent = getVNCIntent();
activity.startActivityForResult(intent, Config.VNC_REQUEST_CODE);
}
public static void startsdl() {
Intent intent = null;
intent = new Intent(activity, MainSDLActivity.class);
android.content.ContentValues values = new android.content.ContentValues();
activity.startActivityForResult(intent, Config.SDL_REQUEST_CODE);
}
public static void resumevm() {
if (vmexecutor != null) {
vmexecutor.resumevm();
UIUtils.toastShort(activity, "VM Reset");
} else {
UIUtils.toastShort(activity, "VM not running");
}
}
public static Intent getVNCIntent() {
return new Intent(activity, com.vectras.qemu.MainVNCActivity.class);
}
public static void goToSettings() {
Intent i = new Intent(activity, MainSettingsManager.class);
activity.startActivity(i);
}
public static void onViewLog() {
Thread t = new Thread(new Runnable() {
public void run() {
FileUtils.viewVectrasLog(activity);
}
});
t.start();
}
public static void goToURL(String url) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
activity.startActivity(i);
}
public static void stopVM(boolean exit) {
execTimer();
Machine.stopVM(activity);
}
public static void stopTimeListener() {
synchronized (lockTime) {
timeQuit = true;
lockTime.notifyAll();
}
}
public static void timer() {
//XXX: No timers just ping a few times
for (int i = 0; i < 3; i++) {
checkAndUpdateStatus(false);
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
public static void checkAndUpdateStatus(boolean force) {
if (vmexecutor != null) {
VMStatus status = checkStatus();
if (force || status != currStatus) {
currStatus = status;
changeStatus(status);
}
}
}
public static void execTimer() {
Thread t = new Thread(new Runnable() {
public void run() {
startTimer();
}
});
t.start();
}
public static void startTimer() {
stopTimeListener();
timeQuit = false;
try {
timer();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static enum VMStatus {
Ready, Stopped, Saving, Paused, Completed, Failed, Unknown, Running
}
public static VMStatus checkStatus() {
VMStatus state = VMStatus.Ready;
if (vmexecutor != null && libLoaded && vmexecutor.get_state().toUpperCase().equals("RUNNING")) {
state = VMStatus.Running;
}
return state;
}
public static class InstallerTask extends AsyncTask<Void, Void, Void> {
public boolean force;
@Override
protected Void doInBackground(Void... arg0) {
onInstall(force);
if (progDialog.isShowing()) {
progDialog.dismiss();
}
return null;
}
@Override
protected void onPostExecute(Void test) {
}
}
}

View file

@ -0,0 +1,20 @@
package com.vectras.qemu;
import android.app.Application;
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
try {
Class.forName("android.os.AsyncTask");
} catch (Throwable ignore) {
// ignored
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
package com.vectras.qemu;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.view.View;
import androidx.core.app.NotificationCompat;
import com.vectras.qemu.jni.StartVM;
import com.vectras.qemu.utils.FileUtils;
import com.vectras.vm.Fragment.HomeFragment;
import com.vectras.vm.MainActivity;
import com.vectras.vm.R;
public class MainService extends Service {
private static final String TAG = "MainService";
private static Notification mNotification;
private static WifiLock mWifiLock;
public static MainService service;
private static WakeLock mWakeLock;
public static boolean isRunning;
private NotificationManager mNotificationManager;
@Override
public IBinder onBind(Intent arg0) {
return null;
}
public static StartVM executor;
private static NotificationCompat.Builder builder;
public static final int notifID = 1000;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
final String action = intent.getAction();
final Bundle b = intent.getExtras();
final int ui = b.getInt("ui", 0);
if (action.equals(Config.ACTION_START)) {
setUpAsForeground(Config.machinename + " VM Running");
FileUtils.startLogging();
scheduleTimer();
Thread t = new Thread(new Runnable() {
public void run() {
//XXX: wait till logging starts capturing
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.v(TAG, "Starting VM " + Config.machinename);
setupLocks();
if (ui == Config.UI_VNC) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
MainActivityCommon.startvnc();
}
}, 2000);
}
//Start vm
String res = executor.startvm();
//VM has exited
MainActivityCommon.cleanup();
}
});
t.setName("StartVM");
t.start();
}
// Don't restart if killed
return START_NOT_STICKY;
}
private void scheduleTimer() {
Thread t = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
MainActivityCommon.startTimer();
}
});
t.start();
}
private void setUpAsForeground(String text) {
isRunning = true;
MainActivityCommon.vmStarted = true;
Class<?> clientClass = null;
if (Config.ui != null) {
if (Config.ui.equals("VNC")) {
if (MainSettingsManager.getVncExternal(MainActivityCommon.activity)) {
MainActivity.extVncLayout.setVisibility(View.VISIBLE);
MainActivity.appbar.setExpanded(true);
}
clientClass = MainVNCActivity.class;
} else if (Config.ui.equals("SDL")) {
clientClass = MainSDLActivity.class;
} else {
Log.e(TAG, "Unknown User Interface");
return;
}
} else {
// UIUtils.toastLong(service, "Machine UI is not set");
//using VNC by default
clientClass = MainVNCActivity.class;
}
Intent intent = new Intent(service.getApplicationContext(), clientClass);
PendingIntent pi = PendingIntent.getActivity(service.getApplicationContext(), 0, intent,
PendingIntent.FLAG_IMMUTABLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel chan = new NotificationChannel(Config.notificationChannelID, Config.notificationChannelName, NotificationManager.IMPORTANCE_NONE);
NotificationManager notifService = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notifService.createNotificationChannel(chan);
builder = new NotificationCompat.Builder(service, Config.notificationChannelID);
} else
builder = new NotificationCompat.Builder(service, "");
mNotification = builder.setContentIntent(pi).setContentTitle(getString(R.string.app_name)).setContentText(text)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(service.getResources(), R.mipmap.ic_launcher)).build();
mNotification.tickerText = text;
mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
service.startForeground(notifID, mNotification);
}
public static void updateServiceNotification(String text) {
if (builder != null) {
builder.setContentText(text);
mNotification = builder.build();
// mNotification.tickerText = text ;
NotificationManager mNotificationManager = (NotificationManager)
service.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(notifID, mNotification);
}
}
@Override
public void onCreate() {
Log.d(TAG, "Creating Service");
service = this;
}
private void setupLocks() {
mWifiLock = ((WifiManager) service.getApplicationContext().getSystemService(Context.WIFI_SERVICE))
.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, Config.wifiLockTag);
mWifiLock.setReferenceCounted(false);
PowerManager pm = (PowerManager) service.getApplicationContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Config.wakeLockTag);
mWakeLock.setReferenceCounted(false);
mNotificationManager = (NotificationManager) service.getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
}
private static void releaseLocks() {
if (mWifiLock != null && mWifiLock.isHeld()) {
Log.d(TAG, "Release Wifi lock...");
mWifiLock.release();
}
if (mWakeLock != null && mWakeLock.isHeld()) {
Log.d(TAG, "Release Wake lock...");
mWakeLock.release();
}
}
public static void stopService() {
Thread t = new Thread(new Runnable() {
public void run() {
releaseLocks();
if (service != null) {
service.stopForeground(true);
service.stopSelf();
isRunning = false;
}
}
});
t.setName("StartVM");
t.start();
}
}

View file

@ -0,0 +1,585 @@
/*
Copyright (C) Max Kastanas 2012
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.vectras.qemu;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragment;
import androidx.preference.PreferenceFragmentCompat;
import com.vectras.vm.R;
import java.util.List;
public class MainSettingsManager extends AppCompatActivity {
private static final String TAG = "SettingsActivity";
public static MainSettingsManager activity;
public static SharedPreferences sp;
public static int fragment = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
activity = this;
fragment = 0;
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setTitle("Settings");
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if(item.getItemId()== android.R.id.home){
if (fragment == 0) {
finish();
} else {
MainFragment.mainFragment();
}
}
return super.onOptionsItemSelected(item);
}
public static class MainFragment extends PreferenceFragmentCompat {
public static MainFragment fr;
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {
setPreferencesFromResource(R.xml.headers_preference, rootKey);
fr = MainFragment.this;
fragment = 0;
findPreference("app").setOnPreferenceClickListener(preference -> {
getFragmentManager().beginTransaction().replace(R.id.settingz,
new AppPreferencesFragment()).commit();
return false;
});
findPreference("userinterface").setOnPreferenceClickListener(preference -> {
getFragmentManager().beginTransaction().replace(R.id.settingz,
new UserInterfacePreferencesFragment()).commit();
return false;
});
findPreference("qemu").setOnPreferenceClickListener(preference -> {
getFragmentManager().beginTransaction().replace(R.id.settingz,
new QemuPreferencesFragment()).commit();
return false;
});
findPreference("vnc").setOnPreferenceClickListener(preference -> {
getFragmentManager().beginTransaction().replace(R.id.settingz,
new VncPreferencesFragment()).commit();
return false;
});
}
public static void mainFragment(){
fr.getFragmentManager().beginTransaction().replace(R.id.settingz,
new MainFragment()).commit();
}
@Override
public void onResume() {
super.onResume();
fragment = 0;
}
@Override
public void onPause() {
super.onPause();
fragment = 0;
}
}
public static class AppPreferencesFragment extends PreferenceFragmentCompat
implements OnSharedPreferenceChangeListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sp = getPreferenceScreen().getSharedPreferences();
Toolbar toolbar = (Toolbar) activity.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
activity.getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setTitle("APP SETTINGS");
fragment = 1;
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.settings, rootKey);
}
@Override
public void onResume() {
super.onResume();
fragment = 1;
}
@Override
public void onPause() {
super.onPause();
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
sp = sharedPreferences;
}
}
public static class UserInterfacePreferencesFragment extends PreferenceFragmentCompat
implements OnSharedPreferenceChangeListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.userinterface);
sp = getPreferenceScreen().getSharedPreferences();
Toolbar toolbar = (Toolbar) activity.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
activity.getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setTitle("USER INTERFACE");
fragment = 2;
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
}
@Override
public void onResume() {
super.onResume();
fragment = 2;
}
@Override
public void onPause() {
super.onPause();
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
sp = sharedPreferences;
}
}
public static class QemuPreferencesFragment extends PreferenceFragmentCompat
implements Preference.OnPreferenceChangeListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.qemu);
sp = getPreferenceScreen().getSharedPreferences();
Toolbar toolbar = (Toolbar) activity.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
activity.getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setTitle("QEMU");
fragment = 3;
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
}
@Override
public void onResume() {
super.onResume();
onMemory();
fragment = 3;
}
private void onMemory() {
//findPreference("memory").setEnabled(getCusRam(activity));
}
@Override
public void onPause() {
super.onPause();
onMemory();
}
@Override
public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
onMemory();
return true;
}
}
public static class VncPreferencesFragment extends PreferenceFragmentCompat
implements OnSharedPreferenceChangeListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.vnc);
sp = getPreferenceScreen().getSharedPreferences();
Toolbar toolbar = (Toolbar) activity.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
activity.getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setTitle("VNC");
fragment = 4;
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
}
@Override
public void onResume() {
super.onResume();
fragment = 4;
}
@Override
public void onPause() {
super.onPause();
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
sp = sharedPreferences;
}
}
static String getDNSServer(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
return prefs.getString("dnsServer", Config.defaultDNSServer);
}
public static void setDNSServer(Activity activity, String dnsServer) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("dnsServer", dnsServer);
edit.apply();
}
public static boolean getVncExternal(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
return prefs.getBoolean("vncExternal", false);
}
public static void setVncExternal(Activity activity, boolean vncExternal) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("vncExternal", vncExternal);
edit.apply();
}
public static int getOrientationSetting(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
int orientation = prefs.getInt("orientation", 0);
// UIUtils.log("Getting First time: " + firstTime);
return orientation;
}
public static void setOrientationSetting(Activity activity, int orientation) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
edit.putInt("orientation", orientation);
edit.apply();
}
public static boolean getPromptUpdateVersion(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
return prefs.getBoolean("updateVersionPrompt", Config.defaultCheckNewVersion);
}
public static void setPromptUpdateVersion(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("updateVersionPrompt", flag);
edit.apply();
// UIUtils.log("Setting First time: ");
}
static boolean getPrio(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
return prefs.getBoolean("HighPrio", false);
}
public static void setPrio(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("HighPrio", flag);
edit.apply();
// UIUtils.log("Setting First time: ");
}
public static boolean getAlwaysShowMenuToolbar(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
return prefs.getBoolean("AlwaysShowMenuToolbar", false);
}
public static void setAlwaysShowMenuToolbar(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("AlwaysShowMenuToolbar", flag);
edit.apply();
// UIUtils.log("Setting First time: ");
}
public static boolean getFullscreen(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
return prefs.getBoolean("ShowFullscreen", true);
}
public static void setFullscreen(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("ShowFullscreen", flag);
edit.apply();
// UIUtils.log("Setting First time: ");
}
public static boolean getDesktopMode(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
return prefs.getBoolean("DesktopMode", false);
}
public static void setDesktopMode(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("DesktopMode", flag);
edit.apply();
// UIUtils.log("Setting First time: ");
}
public static boolean getEnableLegacyFileManager(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
return prefs.getBoolean("EnableLegacyFileManager", false);
}
public static void setEnableLegacyFileManager(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("EnableLegacyFileManager", flag);
edit.apply();
// UIUtils.log("Setting First time: ");
}
public static String getLastDir(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String imagesDir = prefs.getString("lastDir", null);
return imagesDir;
}
public static void setLastDir(Context context, String imagesPath) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("lastDir", imagesPath);
edit.commit();
}
public static String getImagesDir(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String imagesDir = prefs.getString("imagesDir", null);
return imagesDir;
}
public static void setImagesDir(Context context, String imagesPath) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("imagesDir", imagesPath);
edit.commit();
}
public static String getExportDir(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String imagesDir = prefs.getString("exportDir", null);
return imagesDir;
}
public static void setExportDir(Context context, String imagesPath) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("exportDir", imagesPath);
edit.commit();
}
public static String getSharedDir(Context context) {
String lastDir = Environment.getExternalStorageDirectory().getPath();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("sharedDir", lastDir);
}
public static void setSharedDir(Context context, String lastDir) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("sharedDir", lastDir);
edit.apply();
// UIUtils.log("Setting First time: ");
}
public static Boolean getMTTCG(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Boolean MTTCG = prefs.getBoolean("MTTCG", true);
return MTTCG;
}
public static void setMTTCG(Context context, Boolean MTTCG) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("MTTCG", MTTCG);
edit.commit();
}
public static int getCpuCores(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
int cpuCores = prefs.getInt("cpuCores", 1);
return cpuCores;
}
public static void setCpuCores(Context context, int cpuCores) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putInt("cpuCores", cpuCores);
edit.commit();
}
public static int getExitCode(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
int exitCode = prefs.getInt("exitCode", 1);
return exitCode;
}
public static void setExitCode(Context context, int exitCode) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putInt("exitCode", exitCode);
edit.commit();
}
public static int getCpuNum(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
int cpuNum = Integer.parseInt(prefs.getString("cpuNum", "1"));
return cpuNum;
}
public static void setCpuNum(Context context, String cpuNum) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("cpuNum", cpuNum);
edit.commit();
}
public static String getControlMode(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String controlMode = prefs.getString("controlMode", "D");
return controlMode;
}
public static void setControlMode(Context context, String controlMode) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("controlMode", controlMode);
edit.commit();
}
public static void setModeNight(Context context, Boolean nightMode) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("modeNight", nightMode);
edit.commit();
}
public static Boolean getModeNight(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("modeNight", false);
}
public static void setCusRam(Activity activity, Boolean cusRam) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("customMemory", cusRam);
edit.apply();
}
public static boolean getCusRam(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
return prefs.getBoolean("customMemory", false);
}
public static boolean isFirstLaunch(Activity activity) {
PackageInfo pInfo = null;
try {
pInfo = activity.getPackageManager().getPackageInfo(activity.getClass().getPackage().getName(),
PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
boolean firstTime = prefs.getBoolean("firstTime" + pInfo.versionName, true);
return firstTime;
}
public static void setFirstLaunch(Activity activity) {
PackageInfo pInfo = null;
try {
pInfo = activity.getPackageManager().getPackageInfo(activity.getClass().getPackage().getName(),
PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("firstTime" + pInfo.versionName, false);
edit.commit();
}
@Override
public void onBackPressed() {
if (fragment == 0) {
finish();
super.onBackPressed();
} else {
MainFragment.mainFragment();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,100 @@
package com.vectras.qemu;
import static android.content.Context.MODE_PRIVATE;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import androidx.annotation.Nullable;
import androidx.preference.EditTextPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import androidx.preference.SwitchPreferenceCompat;
import com.vectras.qemu.utils.Machine;
import com.vectras.vm.R;
import com.vectras.vm.SplashActivity;
public class SettingsFragment extends PreferenceFragmentCompat {
private Handler mHandler;
public SharedPreferences mPref;
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {
setPreferencesFromResource(R.xml.settings, rootKey);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler();
SharedPreferences.OnSharedPreferenceChangeListener listener;
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
switch (key) {
case "modeNight":
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Intent startActivity = new Intent(getContext(), SplashActivity.class);
int pendingIntentId = 123456;
PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), pendingIntentId, startActivity, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
AlarmManager mgr = (AlarmManager) MainSettingsManager.activity.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 500, pendingIntent);
System.exit(0);
}
}, 300);
getActivity().finish();
break;
case "customMemory":
if (prefs.getBoolean("customMemory", false))
findPreference("memory").setEnabled(true);
else
findPreference("memory").setEnabled(false);
break;
case "MTTCG":
if (prefs.getBoolean("MTTCG", false)) {
findPreference("cpuNum").setEnabled(false);
MainSettingsManager.setCpuCores(getContext(), 1);
} else {
findPreference("cpuNum").setEnabled(true);
}
break;
}
}
};
mPref = getPreferenceManager().getDefaultSharedPreferences(getContext());
if (mPref != null) {
mPref.registerOnSharedPreferenceChangeListener(listener);
}
}
@Override
public void onResume() {
super.onResume();
if (mPref.getBoolean("customMemory", false))
findPreference("memory").setEnabled(true);
else
findPreference("memory").setEnabled(false);
if (mPref.getBoolean("MTTCG", false)) {
findPreference("cpuNum").setEnabled(false);
} else {
findPreference("cpuNum").setEnabled(true);
}
}
}

View file

@ -0,0 +1,868 @@
package com.vectras.qemu.jni;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import com.vectras.qemu.Config;
import com.vectras.qemu.MainActivityCommon;
import com.vectras.qemu.MainSDLActivity;
import com.vectras.qemu.MainService;
import com.vectras.qemu.MainSettingsManager;
import com.vectras.qemu.utils.FileUtils;
import com.vectras.qemu.utils.Machine;
import com.vectras.qemu.utils.QmpClient;
import com.vectras.qemu.utils.RamInfo;
import com.vectras.vm.logger.VectrasStatus;
import com.vectras.vm.utils.UIUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import org.json.JSONException;
import org.json.JSONObject;
public class StartVM {
private static final String TAG = "StartVM";
private static Context context;
String[] params = null;
//native lib
private String libqemu = null;
//qmp server
public int enableqmp;
private String qmp_server;
private int qmp_port;
//state
public int paused;
public String snapshot_name = null;
public String save_state_name = null;
private String save_dir;
public int current_fd = 0;
public String base_dir;
public String dns_addr;
public String append = "";
public boolean busy = false;
public String name;
//ui
public int enablespice = 0;
public String keyboard_layout = Config.defaultKeyboardLayout;
public String mouse = null;
public int enablevnc;
public int vnc_allow_external = 0;
public int qmp_allow_external = 0;
public String vnc_passwd = "vectras";
// cpu/board settings
private String cpu;
private String arch = "x86";
private String machine_type;
private int memory = 128;
private int cpuNum = 1;
public int enablekvm;
public int enable_mttcg;
// disks
public String hda_img_path;
private String hdb_img_path;
private String hdc_img_path;
private String hdd_img_path;
public String shared_folder_path;
public int shared_folder_readonly = 1;
private String hd_cache = "default";
//removable devices
public String cd_iso_path;
public String fda_img_path;
public String fdb_img_path;
public String sd_img_path;
//boot options
private String bootdevice = null;
private String kernel;
private String initrd;
//graphics
private String vga_type = "std";
//audio
public String sound_card;
// net
private String net_cfg = "None";
private String nic_card = null;
private String hostfwd = null;
private String guestfwd = null;
//advanced
private int disableacpi = 0;
private int disablehpet = 0;
private int disabletsc = 0;
public String extra_params;
/**
* @throws Exception
*/
public StartVM(Context context) throws Exception {
name = Config.machinename;
base_dir = Config.getBasefileDir();
save_dir = Config.getMachineDir() + name;
save_state_name = save_dir + "/" + Config.state_filename;
hda_img_path = Config.hda_path;
extra_params = Config.extra_params;
shared_folder_path = Config.sharedFolder;
//extra_params = Config.extra_params;
this.context = context;
this.libqemu = FileUtils.getNativeLibDir(context) + "/libqemu-system-x86_64.so";
this.arch = "x86_64";
this.cpuNum = MainSettingsManager.getCpuNum(MainActivityCommon.activity);
if (MainSettingsManager.getMTTCG(MainActivityCommon.activity))
this.enable_mttcg = 1;
else
this.enable_mttcg = 0;
this.vnc_allow_external = 0;
}
public static void onVMResolutionChanged(int width, int height) {
if (MainSDLActivity.mIsSurfaceReady)
MainSDLActivity.onVMResolutionChanged(width, height);
}
public void print(String[] params) {
VectrasStatus.logInfo("Params:");
Log.d(TAG, "Params:");
for (int i = 0; i < params.length; i++) {
VectrasStatus.logInfo(i + ": " + params[i]);
Log.d(TAG, i + ": " + params[i]);
}
}
public String startvm() {
String res = null;
try {
prepareParams();
} catch (Exception ex) {
UIUtils.toastLong(context, ex.getMessage());
return res;
}
//set the exit code
MainSettingsManager.setExitCode(context, 2);
try {
res = start(Config.storagedir, this.base_dir, this.libqemu, Config.SDLHintScale, params, this.paused, this.save_state_name);
} catch (Exception ex) {
ex.printStackTrace();
Log.e(TAG, "Vectras Exception: " + ex.toString());
}
return res;
}
public void prepareParams() throws Exception {
params = null;
ArrayList<String> paramsList = new ArrayList<String>();
paramsList.add(libqemu);
addUIOptions(paramsList);
addCpuBoardOptions(paramsList);
addDrives(paramsList);
addRemovableDrives(paramsList);
addBootOptions(paramsList);
addGraphicsOptions(paramsList);
addAudioOptions(paramsList);
addNetworkOptions(paramsList);
addAdvancedOptions(paramsList);
addGenericOptions(paramsList);
addStateOptions(paramsList);
params = (String[]) paramsList.toArray(new String[paramsList.size()]);
print(params);
}
private void addStateOptions(ArrayList<String> paramsList) {
if (paused == 1 && this.save_state_name != null && !save_state_name.equals("")) {
int fd_tmp = FileUtils.get_fd(context, save_state_name);
if (fd_tmp < 0) {
Log.e(TAG, "Error while getting fd for: " + save_state_name);
} else {
//Log.i(TAG, "Got new fd "+fd_tmp + " for: " +save_state_name);
paramsList.add("-incoming");
paramsList.add("fd:" + fd_tmp);
}
}
}
private void addUIOptions(ArrayList<String> paramsList) {
if (enablevnc != 0) {
Log.v(TAG, "Enable VNC server");
paramsList.add("-vnc");
if (vnc_allow_external != 0) {
//TODO: Allow connections from External
// Use with x509 auth and TLS for encryption
paramsList.add(":1");
} else {
// Allow connections only from localhost using localsocket without a password
//paramsList.add(Config.defaultVNCHost+":" + Config.defaultVNCPort);
String qmpParams = "unix:";
qmpParams += Config.getLocalVNCSocketPath();
paramsList.add(qmpParams);
}
//Allow monitor console only for VNC,
// SDL for android doesn't support more
// than 1 window
paramsList.add("-monitor");
paramsList.add("vc");
} else if (enablespice != 0) {
//Not working right now
Log.v(TAG, "Enable SPICE server");
paramsList.add("-spice");
String spiceParams = "port=5902";
if (vnc_allow_external != 0 && vnc_passwd != null) {
spiceParams += ",password=";
spiceParams += vnc_passwd;
} else
spiceParams += ",addr=127.0.0.1"; // Allow only connections from localhost without password
spiceParams += ",disable-ticketing";
//argv.add("-chardev");
//argv.add("spicevm");
} else {
//SDL needs explicit keyboard layout
Log.v(TAG, "Disabling VNC server, using SDL instead");
if (keyboard_layout == null) {
paramsList.add("-k");
paramsList.add("en-us");
}
//XXX: monitor, serial, and parallel display crashes cause SDL doesn't support more than 1 window
paramsList.add("-monitor");
paramsList.add("none");
paramsList.add("-serial");
paramsList.add("none");
paramsList.add("-parallel");
paramsList.add("none");
}
if (keyboard_layout != null) {
paramsList.add("-k");
paramsList.add(keyboard_layout);
}
if (mouse != null && !mouse.equals("ps2")) {
paramsList.add("-usb");
paramsList.add("-device");
paramsList.add(mouse);
}
}
private void addAdvancedOptions(ArrayList<String> paramsList) {
if (disableacpi != 0) {
paramsList.add("-no-acpi"); //disable ACPI
}
if (disablehpet != 0) {
paramsList.add("-no-hpet"); // disable HPET
}
//TODO:Extra options
if (extra_params != null && !extra_params.trim().equals("")) {
String[] paramsTmp = extra_params.split(" ");
paramsList.addAll(Arrays.asList(paramsTmp));
}
}
private void addAudioOptions(ArrayList<String> paramsList) {
if (sound_card != null && !sound_card.equals("None")) {
paramsList.add("-soundhw");
paramsList.add(sound_card);
}
}
private void addGenericOptions(ArrayList<String> paramsList) {
paramsList.add("-L");
paramsList.add(base_dir);
//XXX: Snapshots not working currently, use migrate/incoming instead
if (snapshot_name != null && !snapshot_name.equals("")) {
paramsList.add("-loadvm");
paramsList.add(snapshot_name);
}
if (enableqmp != 0) {
paramsList.add("-qmp");
if (qmp_allow_external != 0) {
String qmpParams = "tcp:";
qmpParams += (":" + this.qmp_port);
qmpParams += ",server,nowait";
paramsList.add(qmpParams);
} else {
//Specify a unix local domain as localhost to limit to local connections only
String qmpParams = "unix:";
qmpParams += Config.getLocalQMPSocketPath();
qmpParams += ",server,nowait";
paramsList.add(qmpParams);
}
}
//Enable Tracing log
// argv.add("-D");
// argv.add("/sdcard/vectras/log.txt");
// argv.add("--trace");
// argv.add("events=/sdcard/vectras/tmp/events");
// argv.add("--trace");
// argv.add("file=/sdcard/vectras/tmp/trace");
// paramsList.add("-tb-size");
// paramsList.add("32M"); //Don't increase it crashes
paramsList.add("-overcommit");
paramsList.add("mem-lock=off");
paramsList.add("-rtc");
paramsList.add("base=localtime");
paramsList.add("-nodefaults");
//XXX: Usb redir not working under User mode
//Redirect ports (SSH)
// argv.add("-redir");
// argv.add("5555::22");
}
private void addCpuBoardOptions(ArrayList<String> paramsList) {
//XXX: SMP is not working correctly for some guest OSes
//so we enable multi core only under KVM
// anyway regular emulation is not gaining any benefit unless mttcg is enabled but that
// doesn't work for x86 guests yet
if (this.cpuNum > 1 &&
(enablekvm == 1 || enable_mttcg == 1 || !Config.enableSMPOnlyOnKVM)) {
paramsList.add("-smp");
paramsList.add(this.cpuNum + "");
}
if (machine_type != null && !machine_type.equals("Default")) {
paramsList.add("-M");
paramsList.add(machine_type);
}
//FIXME: something is wrong with quoting that doesn't let sparc qemu find the cpu def
// for now we remove the cpu drop downlist items for sparc
if (this.cpu != null && this.cpu.contains(" "))
cpu = "'" + cpu + "'"; // XXX: needed for sparc cpu names
//XXX: we disable tsc feature for x86 since some guests are kernel panicking
// if the cpu has not specified by user we use the internal qemu32/64
if (disabletsc == 1 && (arch.equals("x86") || arch.equals("x86_64"))) {
if (cpu == null || cpu.equals("Default")) {
if (arch.equals("x86"))
cpu = "qemu32";
else if (arch.equals("x86_64"))
cpu = "qemu64";
}
cpu += ",-tsc";
}
if (this.cpu != null && !cpu.equals("Default")) {
paramsList.add("-cpu");
paramsList.add(cpu);
}
paramsList.add("-m");
paramsList.add(RamInfo.vectrasMemory() + "");
if (enablekvm != 0) {
paramsList.add("-enable-kvm");
} else if (this.enable_mttcg != 0 && Machine.isHost64Bit()) {
//XXX: we should only do this for 64bit hosts
paramsList.add("-accel");
String tcgParams = "tcg";
if (cpuNum > 1)
tcgParams += ",thread=multi";
paramsList.add(tcgParams);
//#endif
}
}
private void addNetworkOptions(ArrayList<String> paramsList) throws Exception {
if (this.net_cfg != null) {
paramsList.add("-net");
if (net_cfg.equals("user")) {
String netParams = net_cfg;
if (hostfwd != null) {
//hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport{,hostfwd=...}
// example forward ssh from guest port 2222 to guest port 22:
// hostfwd=tcp::2222-:22
if (hostfwd.startsWith("hostfwd")) {
throw new Exception("Invalid format for Host Forward, should be: tcp:hostport1:guestport1,udp:hostport2:questport2,...");
}
String[] hostfwdparams = hostfwd.split(",");
for (int i = 0; i < hostfwdparams.length; i++) {
netParams += ",";
String[] hostfwdparam = hostfwdparams[i].split(":");
netParams += ("hostfwd=" + hostfwdparam[0] + "::" + hostfwdparam[1] + "-:" + hostfwdparam[2]);
}
}
if (guestfwd != null) {
netParams += ",";
netParams += guestfwd;
}
paramsList.add(netParams);
} else if (net_cfg.equals("tap")) {
paramsList.add("tap,vlan=0,ifname=tap0,script=no");
} else if (net_cfg.equals("none")) {
paramsList.add("none");
} else {
//Unknown interface
paramsList.add("none");
}
}
if (nic_card != null) {
paramsList.add("-net");
String nicParams = "nic";
if (net_cfg.equals("tap"))
nicParams += ",vlan=0";
if (!nic_card.equals("Default"))
nicParams += (",model=" + nic_card);
paramsList.add(nicParams);
}
}
private void addGraphicsOptions(ArrayList<String> paramsList) {
if (vga_type != null) {
if (vga_type.equals("Default")) {
//do nothing
} else if (vga_type.equals("virtio-gpu-pci")) {
paramsList.add("-device");
paramsList.add(vga_type);
} else if (vga_type.equals("nographic")) {
paramsList.add("-nographic");
} else {
paramsList.add("-vga");
paramsList.add(vga_type);
}
}
}
private void addBootOptions(ArrayList<String> paramsList) {
if (this.bootdevice != null) {
paramsList.add("-boot");
paramsList.add(bootdevice);
}
if (this.kernel != null && !this.kernel.equals("")) {
paramsList.add("-kernel");
paramsList.add(this.kernel);
}
if (initrd != null && !initrd.equals("")) {
paramsList.add("-initrd");
paramsList.add(initrd);
}
if (append != null && !append.equals("")) {
paramsList.add("-append");
paramsList.add(append);
}
}
public void addDrives(ArrayList<String> paramsList) {
if (hda_img_path != null) {
paramsList.add("-drive"); //empty
String param = "index=0";
if (Config.enable_hd_if) {
param += ",if=";
param += Config.hd_if_type;
}
param += ",media=disk";
if (!hda_img_path.equals("")) {
param += ",file=" + hda_img_path;
}
paramsList.add(param);
}
if (hdb_img_path != null) {
paramsList.add("-drive"); //empty
String param = "index=1";
if (Config.enable_hd_if) {
param += ",if=";
param += Config.hd_if_type;
}
param += ",media=disk";
if (!hdb_img_path.equals("")) {
param += ",file=" + hdb_img_path;
}
paramsList.add(param);
}
if (hdc_img_path != null) {
paramsList.add("-drive"); //empty
String param = "index=2";
if (Config.enable_hd_if) {
param += ",if=";
param += Config.hd_if_type;
}
param += ",media=disk";
if (!hdc_img_path.equals("")) {
param += ",file=" + hdc_img_path;
}
paramsList.add(param);
}
if (hdd_img_path != null) {
paramsList.add("-drive"); //empty
String param = "index=3";
if (Config.enable_hd_if) {
param += ",if=";
param += Config.hd_if_type;
}
param += ",media=disk";
if (!hdd_img_path.equals("")) {
param += ",file=" + hdd_img_path;
}
paramsList.add(param);
} else if (shared_folder_path != null) {
//XXX; We use hdd to mount any virtual fat drives
paramsList.add("-drive"); //empty
String driveParams = "index=3";
driveParams += ",media=disk";
if (Config.enable_hd_if) {
driveParams += ",if=";
driveParams += Config.hd_if_type;
}
driveParams += ",format=raw";
driveParams += ",file=fat:";
driveParams += "rw:"; //Always Read/Write
driveParams += shared_folder_path;
paramsList.add(driveParams);
}
}
public void addRemovableDrives(ArrayList<String> paramsList) {
if (cd_iso_path != null) {
paramsList.add("-drive"); //empty
String param = "index=2";
if (Config.enable_hd_if) {
param += ",if=";
param += Config.hd_if_type;
}
param += ",media=cdrom";
if (!cd_iso_path.equals("")) {
param += ",file=" + cd_iso_path;
}
paramsList.add(param);
}
if (Config.enableEmulatedFloppy && fda_img_path != null) {
paramsList.add("-drive"); //empty
String param = "index=0,if=floppy";
if (!fda_img_path.equals("")) {
param += ",file=" + fda_img_path;
}
paramsList.add(param);
}
if (Config.enableEmulatedFloppy && fdb_img_path != null) {
paramsList.add("-drive"); //empty
String param = "index=1,if=floppy";
if (!fdb_img_path.equals("")) {
param += ",file=" + fdb_img_path;
}
paramsList.add(param);
}
if (Config.enableEmulatedSDCard && sd_img_path != null) {
paramsList.add("-device");
paramsList.add("sd-card,drive=sd0,bus=sd-bus");
paramsList.add("-drive");
String param = "if=none,id=sd0";
if (!sd_img_path.equals("")) {
param += ",file=" + sd_img_path;
}
paramsList.add(param);
}
}
//JNI Methods
public native String start(String storage_dir, String base_dir, String lib_path, int sdl_scale_hint, Object[] params, int paused, String save_state_name);
public native String stop(int restart);
public native void setsdlrefreshrate(int value);
public native void setvncrefreshrate(int value);
public native int getsdlrefreshrate();
public native int getvncrefreshrate();
private native int onmouse(int button, int action, int relative, float x, float y);
private native int setrelativemousemode(int relativemousemode);
protected void vncchangepassword(String vnc_passwd) {
String res = QmpClient.sendCommand(QmpClient.changevncpasswd(vnc_passwd));
String desc = null;
if (res != null && !res.equals("")) {
try {
JSONObject resObj = new JSONObject(res);
if (resObj != null && !resObj.equals("") && res.contains("error")) {
String resInfo = resObj.getString("error");
if (resInfo != null && !resInfo.equals("")) {
JSONObject resInfoObj = new JSONObject(resInfo);
desc = resInfoObj.getString("desc");
UIUtils.toastLong(context, "Could not set VNC Password: " + desc);
Log.e(TAG, desc);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
protected String changedev(String dev, String dev_value) {
QmpClient.sendCommand(QmpClient.changedev(dev, dev_value));
String display_dev_value = FileUtils.getFullPathFromDocumentFilePath(dev_value);
return "Changed device: " + dev + " to " + display_dev_value;
}
protected String ejectdev(String dev) {
QmpClient.sendCommand(QmpClient.ejectdev(dev));
return "Ejected device: " + dev;
}
public String startvm(Context context, int ui) {
MainService.executor = this;
Intent i = new Intent(Config.ACTION_START, null, context, MainService.class);
Bundle b = new Bundle();
// b.putString("machine_type", this.machine_type);
b.putInt("ui", ui);
i.putExtras(b);
context.startService(i);
Log.v(TAG, "start VM service");
return "startVMService";
}
public void stopvm(final int restart) {
new Thread(new Runnable() {
@Override
public void run() {
doStopVM(restart);
}
}).start();
}
public void doStopVM(final int restart) {
if (restart == 0) {
MainService.stopService();
//XXX: Wait till service goes down
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (restart != 0) {
QmpClient.sendCommand(QmpClient.reset());
} else {
//XXX: Qmp command only halts the VM but doesn't exit
// so we use force close
// QmpClient.sendCommand(QmpClient.powerDown());
stop(restart);
}
}
public String savevm(String statename) {
// Set to delete previous snapshots after vm resumed
Log.v(TAG, "Save Snapshot");
this.snapshot_name = statename;
String res = null;
//TODO:
//res = QmpClient.sendCommand(QmpClient.saveSnapshot());
return res;
}
public String resumevm() {
// Set to delete previous snapshots after vm resumed
Log.v(TAG, "Resume the VM");
String res = startvm();
Log.d(TAG, res);
return res;
}
public void change_vnc_password() {
Thread thread = new Thread(new Runnable() {
public void run() {
vncchangepassword(vnc_passwd);
}
});
thread.start();
}
public String get_state() {
return null;
}
public void change_dev(final String dev, final String image_path) {
Thread thread = new Thread(new Runnable() {
public void run() {
String image_path_conv = FileUtils.convertDocumentFilePath(image_path);
if (image_path_conv == null || image_path_conv.trim().equals("")) {
StartVM.this.busy = true;
String res = StartVM.this.ejectdev(dev);
Log.d(TAG, res);
StartVM.this.busy = false;
} else if (FileUtils.fileValid(context, image_path_conv)) {
StartVM.this.busy = true;
String res = StartVM.this.changedev(dev, image_path_conv);
Log.d(TAG, res);
StartVM.this.busy = false;
} else {
Log.d(TAG, "File does not exist");
}
}
});
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
}
public int get_fd(String path) {
int fd = FileUtils.get_fd(context, path);
return fd;
}
public int close_fd(int fd) {
int res = FileUtils.close_fd(fd);
return res;
}
public void prepPaths() {
File destDir = new File(save_dir);
if (!destDir.exists()) {
destDir.mkdirs();
}
// Protect the paths from qemu thinking they contain a protocol in the string
this.hda_img_path = FileUtils.convertDocumentFilePath(this.hda_img_path);
if (this.hda_img_path != null && hda_img_path.equals("")) {
hda_img_path = null;
}
this.hdb_img_path = FileUtils.convertDocumentFilePath(this.hdb_img_path);
if (this.hdb_img_path != null && hdb_img_path.equals("")) {
hdb_img_path = null;
}
this.hdc_img_path = FileUtils.convertDocumentFilePath(this.hdc_img_path);
if (this.hdc_img_path != null && hdc_img_path.equals("")) {
hdc_img_path = null;
}
this.hdd_img_path = FileUtils.convertDocumentFilePath(this.hdd_img_path);
if (this.hdd_img_path != null && hdd_img_path.equals("")) {
hdd_img_path = null;
}
// Removable disks
this.cd_iso_path = FileUtils.convertDocumentFilePath(this.cd_iso_path);
this.fda_img_path = FileUtils.convertDocumentFilePath(this.fda_img_path);
this.fdb_img_path = FileUtils.convertDocumentFilePath(this.fdb_img_path);
this.sd_img_path = FileUtils.convertDocumentFilePath(this.sd_img_path);
this.kernel = FileUtils.convertDocumentFilePath(this.kernel);
this.initrd = FileUtils.convertDocumentFilePath(this.initrd);
}
public int setRelativeMouseMode(int relative) {
return setrelativemousemode(relative);
}
public int onVectrasMouse(int button, int action, int relative, float x, float y) {
//XXX: Make sure that mouse motion is not triggering crashes in SDL while resizing
if (!MainSDLActivity.mIsSurfaceReady || MainSDLActivity.isResizing) {
// Log.w(TAG, "onVectrasMouse: Ignoring mouse event surface not ready");
return -1;
}
//XXX: Check boundaries, perhaps not necessary since SDL is also doing the same thing
if (relative == 1
|| (x >= 0 && x <= MainSDLActivity.vm_width && y >= 0 && y <= MainSDLActivity.vm_height)
|| (action == MotionEvent.ACTION_SCROLL)) {
// Log.d(TAG, "onVectrasMouse: B: " + button + ", A: " + action + ", R: " + relative + ", X: " + x + ", Y: " + y);
return onmouse(button, action, relative, x, y);
}
return -1;
}
}

View file

@ -0,0 +1,271 @@
/*
Copyright (C) Max Kastanas 2012
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.vectras.qemu.utils;
import android.app.Activity;
import android.content.res.AssetManager;
import android.net.Uri;
import androidx.documentfile.provider.DocumentFile;
import android.util.Log;
import com.vectras.qemu.Config;
import com.vectras.vm.utils.UIUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author dev
*/
public class FileInstaller {
public static void installFiles(Activity activity, boolean force) {
Log.v("Installer", "Installing files...");
File tmpDir = new File(Config.getBasefileDir());
if (!tmpDir.exists()) {
tmpDir.mkdirs();
}
File tmpDir1 = new File(Config.getMachineDir());
if (!tmpDir1.exists()) {
tmpDir1.mkdirs();
}
//Install base dir
File dir = new File(Config.getBasefileDir());
if (dir.exists() && dir.isDirectory()) {
//don't create again
} else if (dir.exists() && !dir.isDirectory()) {
Log.v("Installer", "Could not create Dir, file found: " + Config.getBasefileDir());
return;
} else if (!dir.exists()) {
dir.mkdir();
}
String destDir = Config.getBasefileDir();
//Get each file in assets under ./roms/ and install in SDCARD
AssetManager am = activity.getResources().getAssets();
String[] files = null;
try {
files = am.list("roms");
} catch (IOException ex) {
Logger.getLogger(FileInstaller.class.getName()).log(Level.SEVERE, null, ex);
Log.v("Installer", "Could not install files: " + ex.getMessage());
return;
}
for (int i = 0; i < files.length; i++) {
//Log.v("Installer", "File: " + files[i]);
String[] subfiles = null;
try {
subfiles = am.list("roms/" + files[i]);
} catch (IOException ex) {
Logger.getLogger(FileInstaller.class.getName()).log(Level.SEVERE, null, ex);
}
if (subfiles != null && subfiles.length > 0) {
//Install base dir
File dir1 = new File(Config.getBasefileDir() + files[i]);
if (dir1.exists() && dir1.isDirectory()) {
//don't create again
} else if (dir1.exists() && !dir1.isDirectory()) {
Log.v("Installer", "Could not create Dir, file found: " + Config.getBasefileDir() + files[i]);
return;
} else if (!dir1.exists()) {
dir1.mkdir();
}
for (int k = 0; k < subfiles.length; k++) {
File file = new File(destDir, files[i] + "/" + subfiles[k]);
if(!file.exists() || force) {
Log.v("Installer", "Installing file: " + file.getPath());
installAssetFile(activity, files[i] + "/" + subfiles[k], destDir, "roms", null);
}
}
} else {
File file = new File(destDir, files[i]);
if(!file.exists() || force) {
Log.v("Installer", "Installing file: " + file.getPath());
installAssetFile(activity, files[i], Config.getBasefileDir(), "roms", null);
}
}
}
// InputStream is = am.open(srcFile);
}
public static boolean installAssetFile(Activity activity, String srcFile,
String destDir, String assetsDir, String destFile) {
try {
AssetManager am = activity.getResources().getAssets(); // get the local asset manager
InputStream is = am.open(assetsDir + "/" + srcFile); // open the input stream for reading
File destDirF = new File(destDir);
if (!destDirF.exists()) {
boolean res = destDirF.mkdirs();
if(!res){
UIUtils.toastShort(activity, "Could not create directory for image");
}
}
if(destFile==null)
destFile=srcFile;
OutputStream os = new FileOutputStream(destDir + "/" + destFile);
byte[] buf = new byte[8092];
int n;
while ((n = is.read(buf)) > 0) {
os.write(buf, 0, n);
}
os.close();
is.close();
return true;
} catch (Exception ex) {
Log.e("Installer", "failed to install file: " + destFile + ", Error:" + ex.getMessage());
return false;
}
}
public static Uri installImageTemplateToSDCard(Activity activity, String srcFile,
Uri destDir, String assetsDir, String destFile) {
DocumentFile destFileF = null;
OutputStream os = null;
InputStream is = null;
Uri uri = null;
try {
DocumentFile dir = DocumentFile.fromTreeUri(activity, destDir);
AssetManager am = activity.getResources().getAssets(); // get the local asset manager
is = am.open(assetsDir + "/" + srcFile); // open the input stream for reading
if(destFile==null)
destFile=srcFile;
//Create the file if doesn't exist
destFileF = dir.findFile(destFile);
if(destFileF == null) {
destFileF = dir.createFile("application/octet-stream", destFile);
}
else {
UIUtils.toastShort(activity, "File exists, choose another filename");
return null;
}
//Write to the dest
os = activity.getContentResolver().openOutputStream(destFileF.getUri());
//OutputStream os = new FileOutputStream(destDir + "/" + destFile);
byte[] buf = new byte[8092];
int n;
while ((n = is.read(buf)) > 0) {
os.write(buf, 0, n);
}
//success
uri = destFileF.getUri();
} catch (Exception ex) {
Log.e("Installer", "failed to install file: " + destFile + ", Error:" + ex.getMessage());
} finally {
if(os!=null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return uri;
}
public static String installImageTemplateToExternalStorage(Activity activity, String srcFile,
String destDir, String assetsDir, String destFile) {
File file = new File(destDir, destFile);
String filePath = null;
OutputStream os = null;
InputStream is = null;
try {
AssetManager am = activity.getResources().getAssets(); // get the local asset manager
is = am.open(assetsDir + "/" + srcFile); // open the input stream for reading
if(destFile==null)
destFile=srcFile;
//Create the file if doesn't exist
if(!file.exists()){
file.createNewFile();
}
else {
UIUtils.toastShort(activity, "File exists, choose another filename");
return null;
}
//Write to the dest
os = new FileOutputStream(file);
//OutputStream os = new FileOutputStream(destDir + "/" + destFile);
byte[] buf = new byte[8092];
int n;
while ((n = is.read(buf)) > 0) {
os.write(buf, 0, n);
}
//success
filePath = file.getAbsolutePath();
} catch (Exception ex) {
Log.e("Installer", "failed to install file: " + destFile + ", Error:" + ex.getMessage());
} finally {
if(os!=null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return filePath;
}
}

View file

@ -0,0 +1,647 @@
/*
Copyright (C) Max Kastanas 2012
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.vectras.qemu.utils;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import androidx.documentfile.provider.DocumentFile;
import android.text.Spannable;
import android.util.Log;
import android.webkit.MimeTypeMap;
import com.vectras.vm.R;
import com.vectras.qemu.Config;
import com.vectras.vm.utils.UIUtils;
/**
* @author dev
*/
public class FileUtils {
private final static String TAG = "FileUtils";
public static HashMap<Integer, FileInfo> fds = new HashMap<Integer, FileInfo>();
public static String getNativeLibDir(Context context) {
return context.getApplicationInfo().nativeLibraryDir;
}
public static String getFullPathFromDocumentFilePath(String filePath) {
filePath = filePath.replaceAll("%3A", "^3A");
int index = filePath.lastIndexOf("^3A");
if (index > 0)
filePath = filePath.substring(index + 3);
if (!filePath.startsWith("/"))
filePath = "/" + filePath;
// filePath = filePath.replaceAll("%2F", "/");
// filePath = filePath.replaceAll("\\^2F", "/");
//remove any spaces encoded by the ASF
try {
filePath = URLDecoder.decode(filePath, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return filePath;
}
public static String getFilenameFromPath(String filePath) {
filePath = filePath.replaceAll("%2F", "/");
filePath = filePath.replaceAll("%3A", "/");
filePath = filePath.replaceAll("\\^2F", "/");
filePath = filePath.replaceAll("\\^3A", "/");
int index = filePath.lastIndexOf("/");
if (index > 0)
return filePath.substring(index + 1);
return filePath;
}
public static String unconvertDocumentFilePath(String filePath) {
if (filePath != null && filePath.startsWith("/content//")) {
filePath = filePath.replace("/content//", "content://");
filePath = filePath.replaceAll("\\^\\^\\^", "%");
}
return filePath;
}
public static String convertDocumentFilePath(String filePath) {
if (filePath != null && filePath.startsWith("content://")) {
filePath = filePath.replace("content://", "/content//");
filePath = filePath.replaceAll("%", "\\^\\^\\^");;
}
return filePath;
}
public static void saveFileContents(String filePath, String contents) {
// TODO: we assume that the contents are of small size so we keep in an array
byteArrayToFile(contents.getBytes(), new File(filePath));
}
public static void byteArrayToFile(byte[] byteData, File filePath) {
try {
FileOutputStream fos = new FileOutputStream(filePath);
fos.write(byteData);
fos.close();
} catch (FileNotFoundException ex) {
System.out.println("FileNotFoundException : " + ex);
} catch (IOException ioe) {
System.out.println("IOException : " + ioe);
}
}
public static InputStream getStreamFromFilePath(Context context, String importFilePath) throws FileNotFoundException {
InputStream stream = null;
if (importFilePath.startsWith("content://")) {
Uri uri = Uri.parse(importFilePath);
String mode = "rw";
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, mode);
return new FileInputStream(pfd.getFileDescriptor());
} else {
return new FileInputStream(importFilePath);
}
}
public static String getFileContents(String filePath) {
File file = new File(filePath);
if(!file.exists())
return "";
StringBuilder builder = new StringBuilder("");
try {
FileInputStream stream = new FileInputStream(file);
byte[] buff = new byte[32768];
int bytesRead = 0;
while ((bytesRead = stream.read(buff, 0, buff.length)) > 0) {
builder.append(new String(buff, "UTF-8"));
}
} catch (Exception e) {
e.printStackTrace();
}
String contents = builder.toString();
return contents;
}
public static void viewVectrasLog(final Activity activity) {
String contents = FileUtils.getFileContents(Config.logFilePath);
if (contents.length() > 50 * 1024)
contents = contents.substring(0, 25 * 1024)
+ "\n.....\n" +
contents.substring(contents.length() - 25 * 1024);
final String finalContents = contents;
final Spannable contentsFormatted = UIUtils.formatAndroidLog(contents);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (Config.viewLogInternally) {
UIUtils.UIAlertLog(activity, "Vectras Log", contentsFormatted);
} else {
try {
Intent intent = new Intent(Intent.ACTION_EDIT);
File file = new File(Config.logFilePath);
Uri uri = Uri.fromFile(file);
intent.setDataAndType(uri, "text/plain");
activity.startActivity(intent);
} catch (Exception ex) {
// UIUtils.toastShort(activity, "Could not find a Text Viewer on your device");
UIUtils.UIAlertLog(activity, "Vectras Log", contentsFormatted);
}
}
}
});
}
public static boolean fileValid(Context context, String path) {
if (path == null || path.equals(""))
return true;
if (path.startsWith("content://") || path.startsWith("/content/")) {
int fd = get_fd(context, path);
if (fd <= 0)
return false;
} else {
File file = new File(path);
return file.exists();
}
return true;
}
//TODO: we should pass the modes from the backend and translate them
// instead of blindly using "rw". ie ISOs should be read only.
public static int get_fd(final Context context, String path) {
synchronized (fds) {
int fd = 0;
if (path == null)
return 0;
// Log.d(TAG, "Opening Filepath: " + path);
if (path.startsWith("/content//") || path.startsWith("content://")) {
String npath = unconvertDocumentFilePath(path);
//Is this needed?
// FileInfo info = getExistingFd(npath);
// if (info!=null) {
// ParcelFileDescriptor pfd = info.pfd;
// fd = pfd.getFd();
// Log.d(TAG, "Retrieved hashed documentfile: " + npath + ", FD: " + fd);
// return fd;
// }
// Log.d(TAG, "Opening unconverted: " + npath);
try {
Uri uri = Uri.parse(npath);
String mode = "rw";
if (path.toLowerCase().endsWith(".iso"))
mode = "r";
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, mode);
fd = pfd.getFd();
// Log.d(TAG, "Opening DocumentFile: " + npath + ", FD: " + fd);
fds.put(fd, new FileInfo(path, npath, pfd));
} catch (Exception e) {
Log.e(TAG, "Could not open DocumentFile: " + npath + ", FD: " + fd);
if(Config.debug)
e.printStackTrace();
}
} else {
//Is this needed?
// FileInfo info = getExistingFd(path);
// if (info!=null) {
// ParcelFileDescriptor pfd = info.pfd;
// fd = pfd.getFd();
// Log.d(TAG, "Retrieved hashed file: " + path + ", FD: " + fd);
// return fd;
// }
try {
int mode = ParcelFileDescriptor.MODE_READ_WRITE;
if (path.toLowerCase().endsWith(".iso"))
mode = ParcelFileDescriptor.MODE_READ_ONLY;
File file = new File(path);
if (!file.exists())
file.createNewFile();
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, mode);
fd = pfd.getFd();
fds.put(fd, new FileInfo(path, path, pfd));
Log.d(TAG, "Opening File: " + path + ", FD: " + fd);
} catch (Exception e) {
Log.e(TAG, "Could not open File: " + path + ", FD: " + fd);
if(Config.debug)
e.printStackTrace();
}
}
return fd;
}
}
private static FileInfo getExistingFd(String npath) {
Set<Map.Entry<Integer, FileInfo>> fileInfoSet = fds.entrySet();
Iterator<Map.Entry<Integer, FileInfo>> iter = fileInfoSet.iterator();
while (iter.hasNext()) {
Map.Entry<Integer, FileInfo> entry = iter.next();
FileInfo fileInfo = entry.getValue();
if (fileInfo.npath.equals(npath)) {
return fileInfo;
}
}
return null;
}
public static void close_fds() {
synchronized (fds) {
Integer[] fds = FileUtils.fds.keySet().toArray(new Integer[FileUtils.fds.keySet().size()]);
for (int i = 0; i < fds.length; i++) {
FileUtils.close_fd(fds[i]);
}
}
}
public static int close_fd(int fd) {
if(!Config.closeFileDescriptors) {
return 0;
}
synchronized (fds) {
// Log.d(TAG, "Closing FD: " + fd);
if (FileUtils.fds.containsKey(fd)) {
FileInfo info = FileUtils.fds.get(fd);
try {
ParcelFileDescriptor pfd = info.pfd;
try {
pfd.getFileDescriptor().sync();
} catch (IOException e) {
if(Config.debug) {
Log.w(TAG, "Syncing DocumentFile: " + info.path + ": " + fd + " : " + e);
e.printStackTrace();
}
}
// Log.d(TAG, "Closing DocumentFile: " + info.npath + ", FD: " + fd);
pfd.close();
FileUtils.fds.remove(fd);
return 0; // success for Native side
} catch (IOException e) {
Log.e(TAG, "Error Closing DocumentFile: " + info.path + ": " + fd + " : " + e);
if(Config.debug)
e.printStackTrace();
}
} else {
ParcelFileDescriptor pfd = null;
String path = "unknown";
try {
//xxx: check the hash
FileInfo info = FileUtils.fds.get(fd);
if(info!=null) {
pfd = info.pfd;
path = info.path;
// Log.d(TAG, "Closing hashe File FD: " + fd + ": " + info.path);
}
//xxx: else get a new parcel
if(pfd == null)
pfd = ParcelFileDescriptor.fromFd(fd);
// Log.d(TAG, "Closing File FD: " + fd);
try {
pfd.getFileDescriptor().sync();
} catch (IOException e) {
if(Config.debug) {
Log.e(TAG, "Error Syncing File: " + path + ": " + fd + " : " + e);
e.printStackTrace();
}
}
pfd.close();
return 0;
} catch (Exception e) {
Log.e(TAG, "Error Closing File FD: " + path + ": " + fd + " : " + e);
if(Config.debug)
e.printStackTrace();
}
}
return -1;
}
}
public static void startLogging() {
if (Config.logFilePath == null) {
Log.e(TAG, "Log file is not setup");
return;
}
Thread t = new Thread(new Runnable() {
public void run() {
FileOutputStream os = null;
File logFile = null;
try {
logFile = new File(Config.logFilePath);
if (logFile.exists()) {
logFile.delete();
}
logFile.createNewFile();
Runtime.getRuntime().exec("logcat -c");
Process process = Runtime.getRuntime().exec("logcat v main");
os = new FileOutputStream(logFile);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder log = new StringBuilder("");
String line = "";
while ((line = bufferedReader.readLine()) != null) {
log.setLength(0);
log.append(line).append("\n");
os.write(log.toString().getBytes("UTF-8"));
os.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.flush();
os.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
t.setName("VectrasLogger");
t.start();
}
public static String LoadFile(Activity activity, String fileName, boolean loadFromRawFolder) throws IOException {
// Create a InputStream to read the file into
InputStream iS;
if (loadFromRawFolder) {
// get the resource id from the file name
int rID = activity.getResources().getIdentifier(activity.getClass().getPackage().getName() + ":raw/" + fileName,
null, null);
// get the file as a stream
iS = activity.getResources().openRawResource(rID);
} else {
// get the file as a stream
iS = activity.getResources().getAssets().open(fileName);
}
ByteArrayOutputStream oS = new ByteArrayOutputStream();
byte[] buffer = new byte[iS.available()];
int bytesRead = 0;
while ((bytesRead = iS.read(buffer)) > 0) {
oS.write(buffer);
}
oS.close();
iS.close();
// return the output stream as a String
return oS.toString();
}
public static String getExtensionFromFilename(String fileName) {
if (fileName == null)
return "";
int index = fileName.lastIndexOf(".");
if (index >= 0) {
return fileName.substring(index + 1);
} else
return "";
}
public static int getIconForFile(String file) {
// file = file.toLowerCase();
// String ext = FileUtils.getExtensionFromFilename(file).toLowerCase();
//
// if(ext.equals("img") || ext.equals("qcow")
// || ext.equals("qcow2") || ext.equals("vmdk") || ext.equals("vdi") || ext.equals("cow")
// || ext.equals("dmg") || ext.equals("bochs") || ext.equals("vpc")
// || ext.equals("vhd") || ext.equals("fs"))
// return R.drawable.harddisk;
// else if(ext.equals("iso"))
// return R.drawable.cd;
// else if(ext.equals("ima"))
// return R.drawable.floppy;
// else if(ext.equals("csv"))
// return R.drawable.importvms;
// else if(file.contains("kernel") || file.contains("vmlinuz") || file.contains("initrd"))
// return R.drawable.sysfile;
// else
// return R.drawable.close;
return R.mipmap.ic_launcher;
//
}
public static Uri saveLogFileSDCard(Activity activity,
Uri destDir) {
DocumentFile destFileF = null;
OutputStream os = null;
Uri uri = null;
try {
String logFileContents = getFileContents(Config.logFilePath);
DocumentFile dir = DocumentFile.fromTreeUri(activity, destDir);
//Create the file if doesn't exist
destFileF = dir.findFile(Config.destLogFilename);
if(destFileF == null) {
destFileF = dir.createFile(MimeTypeMap.getSingleton().getMimeTypeFromExtension("txt"), Config.destLogFilename);
}
//Write to the dest
os = activity.getContentResolver().openOutputStream(destFileF.getUri());
os.write(logFileContents.getBytes());
//success
uri = destFileF.getUri();
} catch (Exception ex) {
UIUtils.toastShort(activity, "Failed to save log file: " + ex.getMessage());
} finally {
if(os!=null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return uri;
}
public static String saveLogFileLegacy(Activity activity,
String destLogFilePath) {
String filePath = null;
File destFileF = new File(destLogFilePath, Config.destLogFilename);
try {
String logFileContents = getFileContents(Config.logFilePath);
FileUtils.saveFileContents(destFileF.getAbsolutePath(), logFileContents);
//success
filePath = destFileF.getAbsolutePath();
} catch (Exception ex) {
UIUtils.toastShort(activity, "Failed to save log file: " + destFileF.getAbsolutePath() + ", Error:" + ex.getMessage());
} finally {
}
return filePath;
}
public static String getFileUriFromIntent(Activity activity, Intent data, boolean write) {
if(data == null)
return null;
Uri uri = data.getData();
DocumentFile pickedFile = DocumentFile.fromSingleUri(activity, uri);
String file = uri.toString();
if (!file.contains("com.android.externalstorage.documents")) {
UIUtils.showFileNotSupported(activity);
return null;
}
activity.grantUriPermission(activity.getPackageName(), uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
if(write)
activity.grantUriPermission(activity.getPackageName(), uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
activity.grantUriPermission(activity.getPackageName(), uri, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
int takeFlags = data.getFlags() & Intent.FLAG_GRANT_READ_URI_PERMISSION;
if(write)
takeFlags = takeFlags | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
activity.getContentResolver().takePersistableUriPermission(uri, takeFlags);
return file;
}
public static String getDirPathFromIntent(Activity activity, Intent data) {
if(data == null)
return null;
Bundle b = data.getExtras();
String file = b.getString("currDir");
return file;
}
public static String getFilePathFromIntent(Activity activity, Intent data) {
if(data == null)
return null;
Bundle b = data.getExtras();
String file = b.getString("file");
return file;
}
public static class FileInfo {
public String path;
public String npath;
public ParcelFileDescriptor pfd;
public FileInfo(String path, String npath, ParcelFileDescriptor pfd) {
this.npath = npath;
this.path = path;
this.pfd = pfd;
}
}
public static void saveLogToFile(final Activity activity, final String logFileDestDir) {
Thread t = new Thread(new Runnable() {
public void run() {
String displayName = null;
if (logFileDestDir.startsWith("content://")) {
Uri exportDirUri = Uri.parse(logFileDestDir);
Uri fileCreatedUri = FileUtils.saveLogFileSDCard(activity,
exportDirUri);
displayName = FileUtils.getFullPathFromDocumentFilePath(fileCreatedUri.toString());
} else {
String filePath = FileUtils.saveLogFileLegacy(activity, logFileDestDir);
displayName = filePath;
}
if(displayName!=null){
UIUtils.toastShort(activity, "Logfile saved");
}
}
});
t.start();
}
}

View file

@ -0,0 +1,222 @@
package com.vectras.qemu.utils;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.vectras.qemu.Config;
import com.vectras.qemu.MainActivityCommon;
import com.vectras.vm.R;
import com.vectras.vm.utils.UIUtils;
import org.json.JSONException;
import org.json.JSONObject;
public class Machine {
public static final String EMPTY = "empty";
public static String TAG = "Machine";
public static void promptPausedVM(final Activity activity) {
new AlertDialog.Builder(activity, R.style.MainDialogTheme).setCancelable(false).setTitle("Paused").setMessage("VM is now Paused tap OK to exit")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Log.i(TAG, "VM Paused, Shutting Down");
if (activity.getParent() != null) {
activity.getParent().finish();
} else {
activity.finish();
}
if (MainActivityCommon.vmexecutor != null) {
MainActivityCommon.vmexecutor.stopvm(0);
}
}
}).show();
}
public static void onRestartVM(final Context context) {
Thread t = new Thread(new Runnable() {
public void run() {
if (MainActivityCommon.vmexecutor != null) {
Log.v(TAG, "Restarting the VM...");
MainActivityCommon.vmexecutor.stopvm(1);
MainActivityCommon.vmStarted = true;
if(Config.showToast)
UIUtils.toastShort(context, "VM Reset");
} else {
if(Config.showToast)
UIUtils.toastShort(context, "VM Not Running");
}
}
});
t.start();
}
public static void pausedErrorVM(Activity activity, String errStr) {
errStr = errStr != null ? errStr : "Could not pause VM. View log for details";
new AlertDialog.Builder(activity, R.style.MainDialogTheme).setTitle("Error").setMessage(errStr)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Thread t = new Thread(new Runnable() {
public void run() {
String command = QmpClient.cont();
String msg = QmpClient.sendCommand(command);
}
});
t.start();
}
}).show();
}
public static void stopVM(final Activity activity) {
new AlertDialog.Builder(activity, R.style.MainDialogTheme).setTitle("Shutdown VM")
.setMessage("To avoid any corrupt data make sure you "
+ "have already shutdown the Operating system from within the VM. Continue?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (activity.getParent() != null) {
activity.getParent().finish();
} else {
activity.finish();
}
if (MainActivityCommon.vmexecutor != null) {
MainActivityCommon.vmexecutor.stopvm(0);
}
}
}).setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
}).show();
}
public static MainActivityCommon.VMStatus checkSaveVMStatus(final Activity activity) {
String pause_state = "";
if (MainActivityCommon.vmexecutor != null) {
String command = QmpClient.query_migrate();
String res = QmpClient.sendCommand(command);
if (res != null && !res.equals("")) {
//Log.d(TAG, "Migrate status: " + res);
try {
JSONObject resObj = new JSONObject(res);
String resInfo = resObj.getString("return");
JSONObject resInfoObj = new JSONObject(resInfo);
pause_state = resInfoObj.getString("status");
} catch (JSONException e) {
if (Config.debug)
Log.e(TAG,e.getMessage());
//e.printStackTrace();
}
if (pause_state != null && pause_state.toUpperCase().equals("FAILED")) {
Log.e(TAG, "Error: " + res);
}
}
}
if (pause_state.toUpperCase().equals("ACTIVE")) {
return MainActivityCommon.VMStatus.Saving;
} else if (pause_state.toUpperCase().equals("COMPLETED")) {
MainActivityCommon.vmexecutor.paused = 1;
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
promptPausedVM(activity);
}
}, 1000);
return MainActivityCommon.VMStatus.Completed;
} else if (pause_state.toUpperCase().equals("FAILED")) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
pausedErrorVM(activity, null);
}
}, 100);
return MainActivityCommon.VMStatus.Failed;
}
return MainActivityCommon.VMStatus.Unknown;
}
public static boolean isHostX86_64() {
if(Build.SUPPORTED_64_BIT_ABIS != null)
{
for(int i=0; i< Build.SUPPORTED_64_BIT_ABIS.length ; i++)
if(Build.SUPPORTED_64_BIT_ABIS[i].equals("x86_64"))
return true;
}
return false;
}
public static boolean isHostX86() {
if(Build.SUPPORTED_32_BIT_ABIS != null)
{
for(int i=0; i< Build.SUPPORTED_32_BIT_ABIS.length ; i++)
if(Build.SUPPORTED_32_BIT_ABIS[i].equals("x86"))
return true;
}
return false;
}
public static boolean isHostArm() {
if(Build.SUPPORTED_32_BIT_ABIS != null)
{
for(int i=0; i< Build.SUPPORTED_32_BIT_ABIS.length ; i++)
if(Build.SUPPORTED_32_BIT_ABIS[i].equals("armeabi-v7a"))
return true;
}
return false;
}
public static boolean isHostArmv8() {
if(Build.SUPPORTED_64_BIT_ABIS != null)
{
for(int i=0; i< Build.SUPPORTED_64_BIT_ABIS.length ; i++)
if(Build.SUPPORTED_64_BIT_ABIS[i].equals("arm64-v8a"))
return true;
}
return false;
}
public static boolean isHost64Bit() {
return Build.SUPPORTED_64_BIT_ABIS!=null && Build.SUPPORTED_64_BIT_ABIS.length > 0 ;
}
public static void resetVM(final Activity activity) {
new AlertDialog.Builder(activity, R.style.MainDialogTheme).setTitle("Reset VM")
.setMessage("To avoid any corrupt data make sure you "
+ "have already shutdown the Operating system from within the VM. Continue?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
new Thread(new Runnable() {
public void run() {
Log.v(TAG, "VM is reset");
Machine.onRestartVM(activity);
}
}).start();
}
}).setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
}).show();
}
}

View file

@ -0,0 +1,277 @@
package com.vectras.qemu.utils;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.util.Log;
import com.vectras.qemu.Config;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class QmpClient {
private static final String TAG = "QmpClient";
private static String requestCommandMode = "{ \"execute\": \"qmp_capabilities\" }";
public static boolean allow_external = false;
public synchronized static String sendCommand(String command) {
String response = null;
int trial=0;
Socket pingSocket = null;
LocalSocket localSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
if(allow_external) {
pingSocket = new Socket(Config.QMPServer, Config.QMPPort);
pingSocket.setSoTimeout(5000);
out = new PrintWriter(pingSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(pingSocket.getInputStream()));
} else {
localSocket = new LocalSocket();
String localQMPSocketPath = Config.getLocalQMPSocketPath();
LocalSocketAddress localSocketAddr = new LocalSocketAddress(localQMPSocketPath, LocalSocketAddress.Namespace.FILESYSTEM);
localSocket.connect(localSocketAddr);
localSocket.setSoTimeout(5000);
out = new PrintWriter(localSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(localSocket.getInputStream()));
}
sendRequest(out, QmpClient.requestCommandMode);
while(true){
response = getResponse(in);
if(response == null || response.equals("") || trial <10)
break;
Thread.sleep(1000);
trial++;
}
sendRequest(out, command);
trial=0;
while((response = getResponse(in)).equals("") && trial < 10){
Thread.sleep(1000);
trial++;
}
} catch (java.net.ConnectException e) {
Log.w(TAG, "Could not connect to QMP: " + e);
if(Config.debugQmp)
e.printStackTrace();
} catch(Exception e) {
// TODO Auto-generated catch block
Log.e(TAG, "Error while connecting to QMP: " + e);
if(Config.debugQmp)
e.printStackTrace();
} finally {
if (out != null)
out.close();
try {
if (in != null)
in.close();
if (pingSocket != null)
pingSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return response;
}
private static void sendRequest(PrintWriter out, String request) {
if(Config.debugQmp)
Log.i(TAG, "QMP request" + request);
out.println(request);
}
private static String getResponse(BufferedReader in) throws Exception {
String line;
StringBuilder stringBuilder = new StringBuilder("");
try {
do {
line = in.readLine();
if (line != null) {
if(Config.debugQmp)
Log.i(TAG, "QMP response: " + line);
JSONObject object = new JSONObject(line);
String returnStr = null;
String errStr = null;
try {
if(line.contains("return"))
returnStr = object.getString("return");
} catch (Exception ex) {
if(Config.debugQmp)
ex.printStackTrace();
}
if (returnStr != null) {
stringBuilder.append(line);
stringBuilder.append("\n");
break;
}
try {
if(line.contains("error"))
errStr = object.getString("error");
} catch (Exception ex) {
if(Config.debugQmp)
ex.printStackTrace();
}
stringBuilder.append(line);
stringBuilder.append("\n");
if (errStr != null) {
break;
}
} else
break;
} while (true);
} catch (Exception ex) {
Log.e(TAG, "Could not get Response: " + ex.getMessage());
if(Config.debugQmp)
ex.printStackTrace();
}
return stringBuilder.toString();
}
private static String getQueryMigrateResponse(BufferedReader in) throws Exception {
String line;
StringBuilder stringBuilder = new StringBuilder("");
try {
do {
line = in.readLine();
if (line != null) {
if(Config.debugQmp)
Log.i(TAG, "QMP query-migrate response: " + line);
JSONObject object = new JSONObject(line);
String returnStr = null;
String errStr = null;
try {
returnStr = object.getString("return");
} catch (Exception ex) {
}
if (returnStr != null) {
break;
}
try {
errStr = object.getString("error");
} catch (Exception ex) {
}
stringBuilder.append(line);
stringBuilder.append("\n");
if (errStr != null) {
break;
}
} else
break;
} while (true);
} catch (Exception ex) {
}
return stringBuilder.toString();
}
public static String migrate(boolean block, boolean inc, String uri) {
// XXX: Detach should not be used via QMP according to docs
// return "{\"execute\":\"migrate\",\"arguments\":{\"detach\":" + detach
// + ",\"blk\":" + block + ",\"inc\":" + inc
// + ",\"uri\":\"" + uri + "\"},\"id\":\"limbo\"}";
// its better not to use block (full disk copy) cause its slow (though
// safer)
// see qmp-commands.hx for more info
return "{\"execute\":\"migrate\",\"arguments\":{\"blk\":" + block + ",\"inc\":" + inc + ",\"uri\":\"" + uri
+ "\"},\"id\":\"limbo\"}";
}
public static String changevncpasswd(String passwd) {
return "{\"execute\": \"change\", \"arguments\": { \"device\": \"vnc\", \"target\": \"password\", \"arg\": \"" + passwd +"\" } }";
}
public static String ejectdev(String dev) {
return "{ \"execute\": \"eject\", \"arguments\": { \"device\": \""+ dev +"\" } }";
}
public static String changedev(String dev, String value) {
return "{ \"execute\": \"change\", \"arguments\": { \"device\": \""+dev+"\", \"target\": \"" + value + "\" } }";
}
public static String query_migrate() {
return "{ \"execute\": \"query-migrate\" }";
}
public static String save_snapshot(String snapshot_name) {
return "{\"execute\": \"snapshot-create\", \"arguments\": {\"name\": \""+ snapshot_name+"\"} }";
}
public static String query_snapshot() {
return "{ \"execute\": \"query-snapshot-status\" }";
}
public static String stop() {
return "{ \"execute\": \"stop\" }";
}
public static String cont() {
return "{ \"execute\": \"cont\" }";
}
public static String powerDown() {
return "{ \"execute\": \"system_powerdown\" }";
}
public static String reset() {
return "{ \"execute\": \"system_reset\" }";
}
public static String getState() {
return "{ \"execute\": \"query-status\" }";
}
}

View file

@ -0,0 +1,38 @@
package com.vectras.qemu.utils;
import static android.content.Context.ACTIVITY_SERVICE;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.vectras.qemu.MainSettingsManager;
public class RamInfo {
public static Activity activity;
public static int safeLongToInt(long l) {
if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
throw new IllegalArgumentException(l + " cannot be cast to int without changing its value.");
}
return (int) l;
}
public static int vectrasMemory() {
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
ActivityManager activityManager = (ActivityManager) activity.getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long freeMem = mi.availMem / 1048576L;
long totalMem = mi.totalMem / 1048576L;
long usedMem = totalMem - freeMem;
int freeRamInt = safeLongToInt(freeMem);
int totalRamInt = safeLongToInt(totalMem);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
if (prefs.getBoolean("customMemory", false)) {
return Integer.parseInt(prefs.getString("memory", String.valueOf(256)));
} else {
return freeRamInt - 100;
}
}
}