Merge "bootconfig is part of VM identity"
diff --git a/apex/Android.bp b/apex/Android.bp
index 9d6cc94..a2f272e 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -15,6 +15,7 @@
// TODO(jiyong): make it updatable
updatable: false,
+ future_updatable: true,
platform_apis: true,
system_ext_specific: true,
diff --git a/apex/product_packages.mk b/apex/product_packages.mk
index 1a431d5..322b73e 100644
--- a/apex/product_packages.mk
+++ b/apex/product_packages.mk
@@ -25,7 +25,6 @@
# TODO(b/207336449): Figure out how to get these off /system
PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST := \
- system/lib64/libgfxstream_backend.so \
system/framework/oat/%@service-compos.jar@classes.odex \
system/framework/oat/%@service-compos.jar@classes.vdex \
diff --git a/compos/apex/Android.bp b/compos/apex/Android.bp
index 43e75e4..f40da9c 100644
--- a/compos/apex/Android.bp
+++ b/compos/apex/Android.bp
@@ -35,6 +35,7 @@
// TODO(victorhsieh): make it updatable
updatable: false,
+ future_updatable: true,
platform_apis: true,
system_ext_specific: true,
diff --git a/compos/compos_key_cmd/compos_key_cmd.cpp b/compos/compos_key_cmd/compos_key_cmd.cpp
index 76ff06f..27c7275 100644
--- a/compos/compos_key_cmd/compos_key_cmd.cpp
+++ b/compos/compos_key_cmd/compos_key_cmd.cpp
@@ -152,9 +152,13 @@
::ndk::ScopedAStatus onError(int32_t in_cid, int32_t in_error_code,
const std::string& in_message) override {
- // For now, just log the error as onDied() will follow.
LOG(WARNING) << "VM error! cid = " << in_cid << ", error_code = " << in_error_code
<< ", message = " << in_message;
+ {
+ std::unique_lock lock(mMutex);
+ mDied = true;
+ }
+ mCv.notify_all();
return ScopedAStatus::ok();
}
diff --git a/compos/composd/native/Android.bp b/compos/composd/native/Android.bp
index ad0afd9..135f4d4 100644
--- a/compos/composd/native/Android.bp
+++ b/compos/composd/native/Android.bp
@@ -7,12 +7,17 @@
crate_name: "composd_native",
srcs: ["lib.rs"],
rustlibs: [
+ "libanyhow",
"libcxx",
+ "liblibc",
],
static_libs: [
"libcomposd_native_cpp",
],
- shared_libs: ["libcrypto"],
+ shared_libs: [
+ "libartpalette-system",
+ "libcrypto",
+ ],
apex_available: ["com.android.compos"],
}
diff --git a/compos/composd/native/lib.rs b/compos/composd/native/lib.rs
index ace9600..cbec7fd 100644
--- a/compos/composd/native/lib.rs
+++ b/compos/composd/native/lib.rs
@@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-//! Bindings native helpers for composd.
+//! Native helpers for composd.
-pub use ffi::*;
+pub use art::*;
+pub use crypto::*;
#[cxx::bridge]
-mod ffi {
+mod crypto {
/// Contains either a key or a reason why the key could not be extracted.
struct KeyResult {
/// The extracted key. If empty, the attempt to extract the key failed.
@@ -36,3 +37,38 @@
fn extract_rsa_public_key(der_certificate: &[u8]) -> KeyResult;
}
}
+
+mod art {
+ use anyhow::{anyhow, Result};
+ use libc::c_char;
+ use std::ffi::{CStr, OsStr};
+ use std::io::Error;
+ use std::os::unix::ffi::OsStrExt;
+ use std::path::Path;
+ use std::ptr::null;
+
+ // From libartpalette(-system)
+ extern "C" {
+ fn PaletteCreateOdrefreshStagingDirectory(out_staging_dir: *mut *const c_char) -> i32;
+ }
+ const PALETTE_STATUS_OK: i32 = 0;
+ const PALETTE_STATUS_CHECK_ERRNO: i32 = 1;
+
+ /// Creates and returns the staging directory for odrefresh.
+ pub fn palette_create_odrefresh_staging_directory() -> Result<&'static Path> {
+ let mut staging_dir: *const c_char = null();
+ // SAFETY: The C function always returns a non-null C string (after created the directory).
+ let status = unsafe { PaletteCreateOdrefreshStagingDirectory(&mut staging_dir) };
+ match status {
+ PALETTE_STATUS_OK => {
+ // SAFETY: The previously returned `*const c_char` should point to a legitimate C
+ // string.
+ let cstr = unsafe { CStr::from_ptr(staging_dir) };
+ let path = OsStr::from_bytes(cstr.to_bytes()).as_ref();
+ Ok(path)
+ }
+ PALETTE_STATUS_CHECK_ERRNO => Err(anyhow!(Error::last_os_error().to_string())),
+ _ => Err(anyhow!("Failed with palette status {}", status)),
+ }
+ }
+}
diff --git a/compos/composd/src/service.rs b/compos/composd/src/service.rs
index b126710..a2898a2 100644
--- a/compos/composd/src/service.rs
+++ b/compos/composd/src/service.rs
@@ -20,7 +20,6 @@
use crate::compilation_task::CompilationTask;
use crate::fd_server_helper::FdServerConfig;
use crate::instance_manager::InstanceManager;
-use crate::instance_starter::CompOsInstance;
use crate::util::to_binder_result;
use android_system_composd::aidl::android::system::composd::{
ICompilationTask::{BnCompilationTask, ICompilationTask},
@@ -31,12 +30,11 @@
self, BinderFeatures, ExceptionCode, Interface, Status, Strong, ThreadState,
};
use anyhow::{Context, Result};
-use compos_common::COMPOS_DATA_ROOT;
use rustutils::{system_properties, users::AID_ROOT, users::AID_SYSTEM};
-use std::fs::{create_dir, File, OpenOptions};
+use std::fs::{File, OpenOptions};
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
-use std::path::{Path, PathBuf};
+use std::path::Path;
use std::sync::Arc;
pub struct IsolatedCompilationService {
@@ -100,19 +98,12 @@
}
fn do_odrefresh_for_test(&self) -> Result<i8> {
- let mut staging_dir_path = PathBuf::from(COMPOS_DATA_ROOT);
- staging_dir_path.push("test-artifacts");
- to_binder_result(create_dir(&staging_dir_path))?;
-
let compos = self
.instance_manager
.start_test_instance()
.context("Starting CompOS for odrefresh test")?;
- self.do_odrefresh(compos, &staging_dir_path)
- }
- fn do_odrefresh(&self, compos: Arc<CompOsInstance>, staging_dir_path: &Path) -> Result<i8> {
- let output_dir = open_dir(staging_dir_path)?;
+ let output_dir = open_dir(composd_native::palette_create_odrefresh_staging_directory()?)?;
let system_dir = open_dir(Path::new("/system"))?;
// Spawn a fd_server to serve the FDs.
diff --git a/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java b/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
index 685d60c..6cfd0ba 100644
--- a/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
+++ b/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
@@ -18,8 +18,11 @@
import static java.util.Objects.requireNonNull;
+import android.app.job.JobInfo;
import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
import android.app.job.JobService;
+import android.content.ComponentName;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -28,6 +31,7 @@
import android.system.composd.IIsolatedCompilationService;
import android.util.Log;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -37,35 +41,66 @@
*/
public class IsolatedCompilationJobService extends JobService {
private static final String TAG = IsolatedCompilationJobService.class.getName();
+ private static final int DAILY_JOB_ID = 5132250;
+ private static final int STAGED_APEX_JOB_ID = 5132251;
private final AtomicReference<CompilationJob> mCurrentJob = new AtomicReference<>();
+ static void scheduleDailyJob(JobScheduler scheduler) {
+ // TODO(b/205296305) Remove this
+ ComponentName serviceName =
+ new ComponentName("android", IsolatedCompilationJobService.class.getName());
+
+ int result = scheduler.schedule(new JobInfo.Builder(DAILY_JOB_ID, serviceName)
+ .setRequiresDeviceIdle(true)
+ .setRequiresCharging(true)
+ .setPeriodic(TimeUnit.DAYS.toMillis(1))
+ .build());
+ if (result != JobScheduler.RESULT_SUCCESS) {
+ Log.e(TAG, "Failed to schedule daily job");
+ }
+ }
+
+ static void scheduleStagedApexJob(JobScheduler scheduler) {
+ ComponentName serviceName =
+ new ComponentName("android", IsolatedCompilationJobService.class.getName());
+
+ int result = scheduler.schedule(new JobInfo.Builder(STAGED_APEX_JOB_ID, serviceName)
+ // Wait in case more APEXes are staged
+ .setMinimumLatency(TimeUnit.MINUTES.toMillis(60))
+ // We consume CPU, battery, and storage
+ .setRequiresDeviceIdle(true)
+ .setRequiresBatteryNotLow(true)
+ .setRequiresStorageNotLow(true)
+ .build());
+ if (result != JobScheduler.RESULT_SUCCESS) {
+ Log.e(TAG, "Failed to schedule staged APEX job");
+ }
+ }
+
+ static boolean isStagedApexJobScheduled(JobScheduler scheduler) {
+ return scheduler.getPendingJob(STAGED_APEX_JOB_ID) != null;
+ }
+
@Override
public boolean onStartJob(JobParameters params) {
- Log.i(TAG, "starting job");
+ int jobId = params.getJobId();
- CompilationJob oldJob = mCurrentJob.getAndSet(null);
- if (oldJob != null) {
- // This should probably never happen, but just in case
- oldJob.stop();
- }
+ Log.i(TAG, "Starting job " + jobId);
// This function (and onStopJob) are only ever called on the main thread, so we don't have
// to worry about two starts at once, or start and stop happening at once. But onCompletion
// can be called on any thread, so we need to be careful with that.
- CompilationCallback callback = new CompilationCallback() {
- @Override
- public void onSuccess() {
- onCompletion(params, true);
- }
+ CompilationJob oldJob = mCurrentJob.get();
+ if (oldJob != null) {
+ // We're already running a job, give up on this one
+ Log.w(TAG, "Another job is in progress, skipping");
+ return false; // Already finished
+ }
- @Override
- public void onFailure() {
- onCompletion(params, false);
- }
- };
- CompilationJob newJob = new CompilationJob(callback);
+ CompilationJob newJob = new CompilationJob(IsolatedCompilationJobService.this::onCompletion,
+ params);
mCurrentJob.set(newJob);
// This can take some time - we need to start up a VM - so we do it on a separate
@@ -75,9 +110,10 @@
@Override
public void run() {
try {
- newJob.start();
+ newJob.start(jobId);
} catch (RuntimeException e) {
Log.e(TAG, "Starting CompilationJob failed", e);
+ mCurrentJob.set(null);
newJob.stop(); // Just in case it managed to start before failure
jobFinished(params, /*wantReschedule=*/ false);
}
@@ -112,23 +148,23 @@
}
interface CompilationCallback {
- void onSuccess();
-
- void onFailure();
+ void onCompletion(JobParameters params, boolean succeeded);
}
static class CompilationJob extends ICompilationTaskCallback.Stub
implements IBinder.DeathRecipient {
private final AtomicReference<ICompilationTask> mTask = new AtomicReference<>();
private final CompilationCallback mCallback;
+ private final JobParameters mParams;
private volatile boolean mStopRequested = false;
private volatile boolean mCanceled = false;
- CompilationJob(CompilationCallback callback) {
+ CompilationJob(CompilationCallback callback, JobParameters params) {
mCallback = requireNonNull(callback);
+ mParams = params;
}
- void start() {
+ void start(int jobId) {
IBinder binder = ServiceManager.waitForService("android.system.composd");
IIsolatedCompilationService composd =
IIsolatedCompilationService.Stub.asInterface(binder);
@@ -138,8 +174,12 @@
}
try {
- // TODO(b/205296305) Call startStagedApexCompile instead
- ICompilationTask composTask = composd.startTestCompile(this);
+ ICompilationTask composTask;
+ if (jobId == DAILY_JOB_ID) {
+ composTask = composd.startTestCompile(this);
+ } else {
+ composTask = composd.startStagedApexCompile(this);
+ }
mTask.set(composTask);
composTask.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -180,17 +220,18 @@
@Override
public void onSuccess() {
- mTask.set(null);
- if (!mCanceled) {
- mCallback.onSuccess();
- }
+ onCompletion(true);
}
@Override
public void onFailure() {
+ onCompletion(false);
+ }
+
+ private void onCompletion(boolean succeeded) {
mTask.set(null);
if (!mCanceled) {
- mCallback.onFailure();
+ mCallback.onCompletion(mParams, succeeded);
}
}
}
diff --git a/compos/service/java/com/android/server/compos/IsolatedCompilationService.java b/compos/service/java/com/android/server/compos/IsolatedCompilationService.java
index cbc3371..6918572 100644
--- a/compos/service/java/com/android/server/compos/IsolatedCompilationService.java
+++ b/compos/service/java/com/android/server/compos/IsolatedCompilationService.java
@@ -17,17 +17,20 @@
package com.android.server.compos;
import android.annotation.NonNull;
-import android.app.job.JobInfo;
import android.app.job.JobScheduler;
-import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ApexStagedEvent;
+import android.content.pm.IPackageManagerNative;
+import android.content.pm.IStagedApexObserver;
+import android.content.pm.StagedApexInfo;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.provider.DeviceConfig;
import android.util.Log;
import com.android.server.SystemService;
import java.io.File;
-import java.util.concurrent.TimeUnit;
/**
* A system service responsible for performing Isolated Compilation (compiling boot & system server
@@ -37,8 +40,6 @@
*/
public class IsolatedCompilationService extends SystemService {
private static final String TAG = IsolatedCompilationService.class.getName();
- private static final int JOB_ID = 5132250;
- private static final long JOB_PERIOD_MILLIS = TimeUnit.DAYS.toMillis(1);
public IsolatedCompilationService(@NonNull Context context) {
super(context);
@@ -59,24 +60,15 @@
return;
}
- ComponentName serviceName =
- new ComponentName("android", IsolatedCompilationJobService.class.getName());
JobScheduler scheduler = getContext().getSystemService(JobScheduler.class);
if (scheduler == null) {
Log.e(TAG, "No scheduler");
return;
}
- int result =
- scheduler.schedule(
- new JobInfo.Builder(JOB_ID, serviceName)
- .setRequiresDeviceIdle(true)
- .setRequiresCharging(true)
- .setPeriodic(JOB_PERIOD_MILLIS)
- .build());
- if (result != JobScheduler.RESULT_SUCCESS) {
- Log.e(TAG, "Failed to schedule job");
- }
+
+ IsolatedCompilationJobService.scheduleDailyJob(scheduler);
+ StagedApexObserver.registerForStagedApexUpdates(scheduler);
}
private static boolean isIsolatedCompilationSupported() {
@@ -94,4 +86,66 @@
return true;
}
+
+ private static class StagedApexObserver extends IStagedApexObserver.Stub {
+ private final JobScheduler mScheduler;
+ private final IPackageManagerNative mPackageNative;
+
+ static void registerForStagedApexUpdates(JobScheduler scheduler) {
+ final IPackageManagerNative packageNative = IPackageManagerNative.Stub.asInterface(
+ ServiceManager.getService("package_native"));
+ if (packageNative == null) {
+ Log.e(TAG, "No IPackageManagerNative");
+ return;
+ }
+
+ StagedApexObserver observer = new StagedApexObserver(scheduler, packageNative);
+ try {
+ packageNative.registerStagedApexObserver(observer);
+ // In the unlikely event that an APEX has been staged before we get here, we may
+ // have to schedule compilation immediately.
+ observer.checkModules(packageNative.getStagedApexModuleNames());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to initialize observer", e);
+ }
+ }
+
+ private StagedApexObserver(JobScheduler scheduler,
+ IPackageManagerNative packageNative) {
+ mScheduler = scheduler;
+ mPackageNative = packageNative;
+ }
+
+ @Override
+ public void onApexStaged(ApexStagedEvent event) {
+ Log.d(TAG, "onApexStaged");
+ checkModules(event.stagedApexModuleNames);
+ }
+
+ void checkModules(String[] moduleNames) {
+ if (IsolatedCompilationJobService.isStagedApexJobScheduled(mScheduler)) {
+ Log.d(TAG, "Job already scheduled");
+ // We're going to run anyway, we don't need to check this update
+ return;
+ }
+ boolean needCompilation = false;
+ for (String moduleName : moduleNames) {
+ try {
+ StagedApexInfo apexInfo = mPackageNative.getStagedApexInfo(moduleName);
+ if (apexInfo != null && (apexInfo.hasBootClassPathJars
+ || apexInfo.hasDex2OatBootClassPathJars
+ || apexInfo.hasSystemServerClassPathJars)) {
+ Log.i(TAG, "Classpath affecting module updated: " + moduleName);
+ needCompilation = true;
+ break;
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get getStagedApexInfo for " + moduleName);
+ }
+ }
+ if (needCompilation) {
+ IsolatedCompilationJobService.scheduleStagedApexJob(mScheduler);
+ }
+ }
+ }
}
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java b/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java
index 9dbed64..2ddaf30 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineCallback.java
@@ -33,7 +33,12 @@
public interface VirtualMachineCallback {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({ERROR_UNKNOWN, ERROR_PAYLOAD_VERIFICATION_FAILED, ERROR_PAYLOAD_CHANGED})
+ @IntDef({
+ ERROR_UNKNOWN,
+ ERROR_PAYLOAD_VERIFICATION_FAILED,
+ ERROR_PAYLOAD_CHANGED,
+ ERROR_PAYLOAD_INVALID_CONFIG
+ })
@interface ErrorCode {}
/** Error code for all other errors not listed below. */
@@ -48,6 +53,9 @@
/** Error code indicating that the payload is verified, but has changed since the last boot. */
int ERROR_PAYLOAD_CHANGED = 2;
+ /** Error code indicating that the payload config is invalid. */
+ int ERROR_PAYLOAD_INVALID_CONFIG = 3;
+
/** Called when the payload starts in the VM. */
void onPayloadStarted(@NonNull VirtualMachine vm, @Nullable ParcelFileDescriptor stream);
diff --git a/microdroid/keymint/Android.bp b/microdroid/keymint/Android.bp
index a0bbaf4..7915ada 100644
--- a/microdroid/keymint/Android.bp
+++ b/microdroid/keymint/Android.bp
@@ -14,8 +14,10 @@
"-Wall",
"-Wextra",
],
+ defaults: [
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ ],
shared_libs: [
- "android.hardware.security.keymint-V1-ndk",
"lib_android_keymaster_keymint_utils",
"libbase",
"libbinder_ndk",
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 283ecb9..efe6126 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -40,7 +40,7 @@
use vsock::VsockStream;
use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
- ERROR_PAYLOAD_CHANGED, ERROR_PAYLOAD_VERIFICATION_FAILED, ERROR_UNKNOWN, VM_BINDER_SERVICE_PORT, VM_STREAM_SERVICE_PORT, IVirtualMachineService,
+ ERROR_PAYLOAD_CHANGED, ERROR_PAYLOAD_VERIFICATION_FAILED, ERROR_PAYLOAD_INVALID_CONFIG, ERROR_UNKNOWN, VM_BINDER_SERVICE_PORT, VM_STREAM_SERVICE_PORT, IVirtualMachineService,
};
const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
@@ -67,6 +67,8 @@
PayloadChanged(String),
#[error("Payload verification has failed: {0}")]
PayloadVerificationFailed(String),
+ #[error("Payload config is invalid: {0}")]
+ InvalidConfig(String),
}
fn translate_error(err: &Error) -> (i32, String) {
@@ -76,6 +78,7 @@
MicrodroidError::PayloadVerificationFailed(msg) => {
(ERROR_PAYLOAD_VERIFICATION_FAILED, msg.to_string())
}
+ MicrodroidError::InvalidConfig(msg) => (ERROR_PAYLOAD_INVALID_CONFIG, msg.to_string()),
}
} else {
(ERROR_UNKNOWN, err.to_string())
@@ -113,16 +116,27 @@
info!("started.");
let service = get_vms_rpc_binder().context("cannot connect to VirtualMachineService")?;
- if let Err(err) = try_start_payload(&service) {
- let (error_code, message) = translate_error(&err);
- service.notifyError(error_code, &message)?;
- Err(err)
- } else {
- Ok(())
+ match try_run_payload(&service) {
+ Ok(code) => {
+ info!("notifying payload finished");
+ service.notifyPayloadFinished(code)?;
+ if code == 0 {
+ info!("task successfully finished");
+ } else {
+ error!("task exited with exit code: {}", code);
+ }
+ Ok(())
+ }
+ Err(err) => {
+ error!("task terminated: {:?}", err);
+ let (error_code, message) = translate_error(&err);
+ service.notifyError(error_code, &message)?;
+ Err(err)
+ }
}
}
-fn try_start_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<()> {
+fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
let metadata = load_metadata().context("Failed to load payload metadata")?;
let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
@@ -152,27 +166,26 @@
)
.context("Failed to run zipfuse")?;
- if !metadata.payload_config_path.is_empty() {
- let config = load_config(Path::new(&metadata.payload_config_path))?;
+ ensure!(
+ !metadata.payload_config_path.is_empty(),
+ MicrodroidError::InvalidConfig("No payload_config_path in metadata".to_string())
+ );
+ let config = load_config(Path::new(&metadata.payload_config_path))?;
- let fake_secret = "This is a placeholder for a value that is derived from the images that are loaded in the VM.";
- if let Err(err) = rustutils::system_properties::write("ro.vmsecret.keymint", fake_secret) {
- warn!("failed to set ro.vmsecret.keymint: {}", err);
- }
-
- // Wait until apex config is done. (e.g. linker configuration for apexes)
- // TODO(jooyung): wait until sys.boot_completed?
- wait_for_apex_config_done()?;
-
- if let Some(main_task) = &config.task {
- exec_task(main_task, service).map_err(|e| {
- error!("failed to execute task: {}", e);
- e
- })?;
- }
+ let fake_secret = "This is a placeholder for a value that is derived from the images that are loaded in the VM.";
+ if let Err(err) = rustutils::system_properties::write("ro.vmsecret.keymint", fake_secret) {
+ warn!("failed to set ro.vmsecret.keymint: {}", err);
}
- Ok(())
+ // Wait until apex config is done. (e.g. linker configuration for apexes)
+ // TODO(jooyung): wait until sys.boot_completed?
+ wait_for_apex_config_done()?;
+
+ ensure!(
+ config.task.is_some(),
+ MicrodroidError::InvalidConfig("No task in VM config".to_string())
+ );
+ exec_task(&config.task.unwrap(), service)
}
struct ApkDmverityArgument<'a> {
@@ -321,7 +334,7 @@
/// Executes the given task. Stdout of the task is piped into the vsock stream to the
/// virtualizationservice in the host side.
-fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<()> {
+fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
info!("executing main task {:?}...", task);
let mut command = build_command(task)?;
@@ -335,19 +348,7 @@
}
let exit_status = command.spawn()?.wait()?;
- if let Some(code) = exit_status.code() {
- info!("notifying payload finished");
- service.notifyPayloadFinished(code)?;
-
- if code == 0 {
- info!("task successfully finished");
- } else {
- error!("task exited with exit code: {}", code);
- }
- } else {
- error!("task terminated: {}", exit_status);
- }
- Ok(())
+ exit_status.code().ok_or_else(|| anyhow!("Failed to get exit_code from the paylaod."))
}
fn build_command(task: &Task) -> Result<Command> {
diff --git a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
index 97f6ca3..1a16f2a 100644
--- a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
@@ -64,4 +64,9 @@
* Error code indicating that the payload is verified, but has changed since the last boot.
*/
const int ERROR_PAYLOAD_CHANGED = 2;
+
+ /**
+ * Error code indicating that the payload config is invalid.
+ */
+ const int ERROR_PAYLOAD_INVALID_CONFIG = 3;
}