Add API for configuring a VM to run in debug mode

Bug: 185211964
Test: run the demo app
Change-Id: I960839037b2f23dbce1552199d9c9e59c36053e2
This commit is contained in:
Jiyong Park 2021-07-07 12:23:52 +09:00
parent d542e92021
commit af1a74b084
3 changed files with 118 additions and 18 deletions

View File

@ -22,6 +22,10 @@ import android.system.virtualmachine.VirtualMachine;
import android.system.virtualmachine.VirtualMachineConfig;
import android.system.virtualmachine.VirtualMachineException;
import android.system.virtualmachine.VirtualMachineManager;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ScrollView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
@ -47,38 +51,77 @@ public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView consoleView = (TextView) findViewById(R.id.consoleOutput);
Button runStopButton = (Button) findViewById(R.id.runStopButton);
ScrollView scrollView = (ScrollView) findViewById(R.id.scrollview);
// Whenthe console model is updated, append the new line to the text view.
TextView view = (TextView) findViewById(R.id.textview);
// When the console model is updated, append the new line to the text view.
VirtualMachineModel model = new ViewModelProvider(this).get(VirtualMachineModel.class);
model.getConsoleOutput()
.observeForever(
new Observer<String>() {
@Override
public void onChanged(String line) {
view.append(line + "\n");
consoleView.append(line + "\n");
scrollView.fullScroll(View.FOCUS_DOWN);
}
});
// When the VM status is updated, change the label of the button
model.getStatus()
.observeForever(
new Observer<VirtualMachine.Status>() {
@Override
public void onChanged(VirtualMachine.Status status) {
if (status == VirtualMachine.Status.RUNNING) {
runStopButton.setText("Stop");
} else {
runStopButton.setText("Run");
consoleView.setText("");
}
}
});
// When the button is clicked, run or stop the VM
runStopButton.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
if (model.getStatus().getValue() == VirtualMachine.Status.RUNNING) {
model.stop();
} else {
CheckBox debugModeCheckBox = (CheckBox) findViewById(R.id.debugMode);
final boolean debug = debugModeCheckBox.isChecked();
model.run(debug);
}
}
});
}
/** Models a virtual machine and console output from it. */
public static class VirtualMachineModel extends AndroidViewModel {
private final VirtualMachine mVirtualMachine;
private VirtualMachine mVirtualMachine;
private final MutableLiveData<String> mConsoleOutput = new MutableLiveData<>();
private final MutableLiveData<VirtualMachine.Status> mStatus = new MutableLiveData<>();
public VirtualMachineModel(Application app) {
super(app);
mStatus.setValue(VirtualMachine.Status.DELETED);
}
/** Runs a VM */
public void run(boolean debug) {
// Create a VM and run it.
// TODO(jiyong): remove the call to idsigPath
try {
VirtualMachineConfig config =
VirtualMachineConfig.Builder builder =
new VirtualMachineConfig.Builder(getApplication(), "assets/vm_config.json")
.idsigPath("/data/local/tmp/virt/MicrodroidDemoApp.apk.idsig")
.build();
.debugMode(debug);
VirtualMachineConfig config = builder.build();
VirtualMachineManager vmm = VirtualMachineManager.getInstance(getApplication());
mVirtualMachine = vmm.create("demo_vm", config);
mVirtualMachine.run();
mStatus.postValue(mVirtualMachine.getStatus());
} catch (VirtualMachineException e) {
throw new RuntimeException(e);
}
@ -105,8 +148,25 @@ public class MainActivity extends AppCompatActivity {
});
}
/** Stops the running VM */
public void stop() {
try {
mVirtualMachine.stop();
} catch (VirtualMachineException e) {
// Consume
}
mVirtualMachine = null;
mStatus.postValue(VirtualMachine.Status.STOPPED);
}
/** Returns the console output from the VM */
public LiveData<String> getConsoleOutput() {
return mConsoleOutput;
}
/** Returns the status of the VM */
public LiveData<VirtualMachine.Status> getStatus() {
return mStatus;
}
}
}

View File

@ -9,18 +9,43 @@
android:textAlignment="textStart"
tools:context=".MainActivity">
<ScrollView
android:id="@+id/scrollview"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textview"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFEB3B"
android:fontFamily="monospace"
android:textColor="#000000" />
</ScrollView>
android:orientation="horizontal">
<Button
android:id="@+id/runStopButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Run" />
<CheckBox
android:id="@+id/debugMode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Debug mode" />
</LinearLayout>
<ScrollView
android:id="@+id/scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/consoleOutput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFEB3B"
android:fontFamily="monospace"
android:textColor="#000000" />
</ScrollView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -43,10 +43,12 @@ public final class VirtualMachineConfig {
private static final String KEY_APKPATH = "apkPath";
private static final String KEY_IDSIGPATH = "idsigPath";
private static final String KEY_PAYLOADCONFIGPATH = "payloadConfigPath";
private static final String KEY_DEBUGMODE = "debugMode";
// Paths to the APK and its idsig file of this application.
private final String mApkPath;
private final String mIdsigPath;
private final boolean mDebugMode;
/**
* Path within the APK to the payload config file that defines software aspects of this config.
@ -55,10 +57,12 @@ public final class VirtualMachineConfig {
// TODO(jiyong): add more items like # of cpu, size of ram, debuggability, etc.
private VirtualMachineConfig(String apkPath, String idsigPath, String payloadConfigPath) {
private VirtualMachineConfig(
String apkPath, String idsigPath, String payloadConfigPath, boolean debugMode) {
mApkPath = apkPath;
mIdsigPath = idsigPath;
mPayloadConfigPath = payloadConfigPath;
mDebugMode = debugMode;
}
/** Loads a config from a stream, for example a file. */
@ -81,7 +85,8 @@ public final class VirtualMachineConfig {
if (payloadConfigPath == null) {
throw new VirtualMachineException("No payloadConfigPath");
}
return new VirtualMachineConfig(apkPath, idsigPath, payloadConfigPath);
final boolean debugMode = b.getBoolean(KEY_DEBUGMODE);
return new VirtualMachineConfig(apkPath, idsigPath, payloadConfigPath, debugMode);
}
/** Persists this config to a stream, for example a file. */
@ -91,6 +96,7 @@ public final class VirtualMachineConfig {
b.putString(KEY_APKPATH, mApkPath);
b.putString(KEY_IDSIGPATH, mIdsigPath);
b.putString(KEY_PAYLOADCONFIGPATH, mPayloadConfigPath);
b.putBoolean(KEY_DEBUGMODE, mDebugMode);
b.writeToStream(output);
}
@ -110,6 +116,7 @@ public final class VirtualMachineConfig {
parcel.apk = ParcelFileDescriptor.open(new File(mApkPath), MODE_READ_ONLY);
parcel.idsig = ParcelFileDescriptor.open(new File(mIdsigPath), MODE_READ_ONLY);
parcel.configPath = mPayloadConfigPath;
parcel.debug = mDebugMode;
return parcel;
}
@ -117,6 +124,7 @@ public final class VirtualMachineConfig {
public static class Builder {
private Context mContext;
private String mPayloadConfigPath;
private boolean mDebugMode;
private String mIdsigPath; // TODO(jiyong): remove this
// TODO(jiyong): add more items like # of cpu, size of ram, debuggability, etc.
@ -124,6 +132,13 @@ public final class VirtualMachineConfig {
public Builder(Context context, String payloadConfigPath) {
mContext = context;
mPayloadConfigPath = payloadConfigPath;
mDebugMode = false;
}
/** Enables or disables the debug mode */
public Builder debugMode(boolean enableOrDisable) {
mDebugMode = enableOrDisable;
return this;
}
// TODO(jiyong): remove this. Apps shouldn't need to set the path to the idsig file. It
@ -137,7 +152,7 @@ public final class VirtualMachineConfig {
/** Builds an immutable {@link VirtualMachineConfig} */
public VirtualMachineConfig build() {
final String apkPath = mContext.getPackageCodePath();
return new VirtualMachineConfig(apkPath, mIdsigPath, mPayloadConfigPath);
return new VirtualMachineConfig(apkPath, mIdsigPath, mPayloadConfigPath, mDebugMode);
}
}
}