1 /* 2 * Copyright 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.system.virtualmachine; 18 19 import static java.util.Objects.requireNonNull; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SystemApi; 24 import android.os.Parcel; 25 import android.os.ParcelFileDescriptor; 26 import android.os.Parcelable; 27 28 import java.io.IOException; 29 30 /** 31 * A VM descriptor that captures the state of a Virtual Machine. 32 * 33 * <p>You can capture the current state of VM by creating an instance of this class with {@link 34 * VirtualMachine#toDescriptor}, optionally pass it to another App, and then build an identical VM 35 * with the descriptor received. 36 * 37 * @hide 38 */ 39 @SystemApi 40 public final class VirtualMachineDescriptor implements Parcelable, AutoCloseable { 41 private volatile boolean mClosed = false; 42 @NonNull private final ParcelFileDescriptor mConfigFd; 43 // File descriptor of the file containing the instance id - will be null iff 44 // FEATURE_LLPVM_CHANGES is disabled. 45 @Nullable private final ParcelFileDescriptor mInstanceIdFd; 46 @NonNull private final ParcelFileDescriptor mInstanceImgFd; 47 // File descriptor of the image backing the encrypted storage - Will be null if encrypted 48 // storage is not enabled. */ 49 @Nullable private final ParcelFileDescriptor mEncryptedStoreFd; 50 51 @Override describeContents()52 public int describeContents() { 53 return CONTENTS_FILE_DESCRIPTOR; 54 } 55 56 @Override writeToParcel(@onNull Parcel out, int flags)57 public void writeToParcel(@NonNull Parcel out, int flags) { 58 checkNotClosed(); 59 out.writeParcelable(mConfigFd, flags); 60 out.writeParcelable(mInstanceIdFd, flags); 61 out.writeParcelable(mInstanceImgFd, flags); 62 out.writeParcelable(mEncryptedStoreFd, flags); 63 } 64 65 @NonNull 66 public static final Parcelable.Creator<VirtualMachineDescriptor> CREATOR = 67 new Parcelable.Creator<>() { 68 public VirtualMachineDescriptor createFromParcel(Parcel in) { 69 return new VirtualMachineDescriptor(in); 70 } 71 72 public VirtualMachineDescriptor[] newArray(int size) { 73 return new VirtualMachineDescriptor[size]; 74 } 75 }; 76 77 /** 78 * @return File descriptor of the VM configuration file config.xml. 79 */ 80 @NonNull getConfigFd()81 ParcelFileDescriptor getConfigFd() { 82 checkNotClosed(); 83 return mConfigFd; 84 } 85 86 /** 87 * @return File descriptor of the file containing instance_id of the VM. 88 */ 89 @Nullable getInstanceIdFd()90 ParcelFileDescriptor getInstanceIdFd() { 91 checkNotClosed(); 92 return mInstanceIdFd; 93 } 94 95 /** 96 * @return File descriptor of the instance.img of the VM. 97 */ 98 @NonNull getInstanceImgFd()99 ParcelFileDescriptor getInstanceImgFd() { 100 checkNotClosed(); 101 return mInstanceImgFd; 102 } 103 104 /** 105 * @return File descriptor of image backing the encrypted storage. 106 * <p>This method will return null if encrypted storage is not enabled. 107 */ 108 @Nullable getEncryptedStoreFd()109 ParcelFileDescriptor getEncryptedStoreFd() { 110 checkNotClosed(); 111 return mEncryptedStoreFd; 112 } 113 VirtualMachineDescriptor( @onNull ParcelFileDescriptor configFd, @Nullable ParcelFileDescriptor instanceIdFd, @NonNull ParcelFileDescriptor instanceImgFd, @Nullable ParcelFileDescriptor encryptedStoreFd)114 VirtualMachineDescriptor( 115 @NonNull ParcelFileDescriptor configFd, 116 @Nullable ParcelFileDescriptor instanceIdFd, 117 @NonNull ParcelFileDescriptor instanceImgFd, 118 @Nullable ParcelFileDescriptor encryptedStoreFd) { 119 mConfigFd = requireNonNull(configFd); 120 mInstanceIdFd = instanceIdFd; 121 mInstanceImgFd = requireNonNull(instanceImgFd); 122 mEncryptedStoreFd = encryptedStoreFd; 123 } 124 VirtualMachineDescriptor(Parcel in)125 private VirtualMachineDescriptor(Parcel in) { 126 mConfigFd = requireNonNull(readParcelFileDescriptor(in)); 127 mInstanceIdFd = readParcelFileDescriptor(in); 128 mInstanceImgFd = requireNonNull(readParcelFileDescriptor(in)); 129 mEncryptedStoreFd = readParcelFileDescriptor(in); 130 } 131 readParcelFileDescriptor(Parcel in)132 private ParcelFileDescriptor readParcelFileDescriptor(Parcel in) { 133 return in.readParcelable( 134 ParcelFileDescriptor.class.getClassLoader(), ParcelFileDescriptor.class); 135 } 136 137 /** 138 * Release any resources held by this descriptor. Calling {@code close} on an already-closed 139 * descriptor has no effect. 140 */ 141 @Override close()142 public void close() { 143 mClosed = true; 144 // Let the compiler do the work: close everything, throw if any of them fail, skipping null. 145 try (mConfigFd; 146 mInstanceIdFd; 147 mInstanceImgFd; 148 mEncryptedStoreFd) { 149 } catch (IOException ignored) { 150 // PFD already swallows exceptions from closing the fd. There's no reason to propagate 151 // this to the caller. 152 } 153 } 154 checkNotClosed()155 private void checkNotClosed() { 156 if (mClosed) { 157 throw new IllegalStateException("Descriptor has been closed"); 158 } 159 } 160 } 161