Loading core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -39351,8 +39351,10 @@ package android.security { } public final class FileIntegrityManager { method @FlaggedApi(Flags.FLAG_FSVERITY_API) @Nullable public byte[] getFsverityDigest(@NonNull java.io.File) throws java.io.IOException; method public boolean isApkVeritySupported(); method @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public boolean isAppSourceCertificateTrusted(@NonNull java.security.cert.X509Certificate) throws java.security.cert.CertificateEncodingException; method @FlaggedApi(Flags.FLAG_FSVERITY_API) public void setupFsverity(@NonNull java.io.File) throws java.io.IOException; } public final class KeyChain { core/java/android/os/storage/StorageManagerInternal.java +16 −0 Original line number Diff line number Diff line Loading @@ -20,8 +20,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.pm.UserInfo; import android.os.IInstalld; import android.os.IVold; import android.os.ParcelFileDescriptor; import java.io.IOException; import java.util.List; import java.util.Set; Loading Loading @@ -185,4 +188,17 @@ public abstract class StorageManagerInternal { public abstract void prepareUserStorageForMove(String fromVolumeUuid, String toVolumeUuid, List<UserInfo> users); /** * A proxy call to the corresponding method in Installer. * @see com.android.server.pm.Installer#createFsveritySetupAuthToken() */ public abstract IInstalld.IFsveritySetupAuthToken createFsveritySetupAuthToken( ParcelFileDescriptor authFd, int appUid, @UserIdInt int userId) throws IOException; /** * A proxy call to the corresponding method in Installer. * @see com.android.server.pm.Installer#enableFsverity() */ public abstract int enableFsverity(IInstalld.IFsveritySetupAuthToken authToken, String filePath, String packageName) throws IOException; } core/java/android/security/FileIntegrityManager.java +70 −0 Original line number Diff line number Diff line Loading @@ -16,12 +16,21 @@ package android.security; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.content.Context; import android.os.IInstalld.IFsveritySetupAuthToken; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.system.ErrnoException; import com.android.internal.security.VerityUtils; import java.io.File; import java.io.IOException; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; Loading Loading @@ -54,6 +63,67 @@ public final class FileIntegrityManager { } } /** * Enables fs-verity to the owned file under the calling app's private directory. It always uses * the common configuration, i.e. SHA-256 digest algorithm, 4K block size, and without salt. * * The operation can only succeed when the file is not opened as writable by any process. * * It takes O(file size) time to build the underlying data structure for continuous * verification. The operation is atomic, i.e. it's either enabled or not, even in case of * power failure during or after the call. * * Note for the API users: When the file's authenticity is crucial, the app typical needs to * perform a signature check by itself before using the file. The signature is often delivered * as a separate file and stored next to the targeting file in the filesystem. The public key of * the signer (normally the same app developer) can be put in the APK, and the app can use the * public key to verify the signature to the file's actual fs-verity digest (from {@link * #getFsverityDigest}) before using the file. The exact format is not prescribed by the * framework. App developers may choose to use common practices like JCA for the signing and * verification, or their own preferred approach. * * @param file The file to enable fs-verity. It should be an absolute path. * * @see <a href="https://www.kernel.org/doc/html/next/filesystems/fsverity.html">Kernel doc</a> */ @FlaggedApi(Flags.FLAG_FSVERITY_API) public void setupFsverity(@NonNull File file) throws IOException { if (!file.isAbsolute()) { throw new IllegalArgumentException("Expect an absolute path"); } IFsveritySetupAuthToken authToken; // fs-verity setup requires no writable fd to the file. Make sure it's closed before // continue. try (var authFd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE)) { authToken = mService.createAuthToken(authFd); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } try { int errno = mService.setupFsverity(authToken, file.getPath(), mContext.getPackageName()); if (errno != 0) { new ErrnoException("setupFsverity", errno).rethrowAsIOException(); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns the fs-verity digest for the owned file under the calling app's * private directory, or null when the file does not have fs-verity enabled. * * @param file The file to measure the fs-verity digest. * @return The fs-verity digeset in byte[], null if none. * @see <a href="https://www.kernel.org/doc/html/next/filesystems/fsverity.html">Kernel doc</a> */ @FlaggedApi(Flags.FLAG_FSVERITY_API) public @Nullable byte[] getFsverityDigest(@NonNull File file) throws IOException { return VerityUtils.getFsverityDigest(file.getPath()); } /** * Returns whether the given certificate can be used to prove app's install source. Always * return false if the feature is not supported. Loading core/java/android/security/IFileIntegrityService.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.security; import android.os.ParcelFileDescriptor; import android.os.IInstalld; /** * Binder interface to communicate with FileIntegrityService. * @hide Loading @@ -23,4 +26,8 @@ package android.security; interface IFileIntegrityService { boolean isApkVeritySupported(); boolean isAppSourceCertificateTrusted(in byte[] certificateBytes, in String packageName); IInstalld.IFsveritySetupAuthToken createAuthToken(in ParcelFileDescriptor authFd); int setupFsverity(IInstalld.IFsveritySetupAuthToken authToken, in String filePath, in String packageName); } services/core/java/com/android/server/StorageManagerService.java +20 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.IInstalld.IFsveritySetupAuthToken; import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED; import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT; Loading Loading @@ -4994,5 +4995,24 @@ class StorageManagerService extends IStorageManager.Stub } } @Override public IFsveritySetupAuthToken createFsveritySetupAuthToken(ParcelFileDescriptor authFd, int appUid, @UserIdInt int userId) throws IOException { try { return mInstaller.createFsveritySetupAuthToken(authFd, appUid, userId); } catch (Installer.InstallerException e) { throw new IOException(e); } } @Override public int enableFsverity(IFsveritySetupAuthToken authToken, String filePath, String packageName) throws IOException { try { return mInstaller.enableFsverity(authToken, filePath, packageName); } catch (Installer.InstallerException e) { throw new IOException(e); } } } } Loading
core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -39351,8 +39351,10 @@ package android.security { } public final class FileIntegrityManager { method @FlaggedApi(Flags.FLAG_FSVERITY_API) @Nullable public byte[] getFsverityDigest(@NonNull java.io.File) throws java.io.IOException; method public boolean isApkVeritySupported(); method @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public boolean isAppSourceCertificateTrusted(@NonNull java.security.cert.X509Certificate) throws java.security.cert.CertificateEncodingException; method @FlaggedApi(Flags.FLAG_FSVERITY_API) public void setupFsverity(@NonNull java.io.File) throws java.io.IOException; } public final class KeyChain {
core/java/android/os/storage/StorageManagerInternal.java +16 −0 Original line number Diff line number Diff line Loading @@ -20,8 +20,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.pm.UserInfo; import android.os.IInstalld; import android.os.IVold; import android.os.ParcelFileDescriptor; import java.io.IOException; import java.util.List; import java.util.Set; Loading Loading @@ -185,4 +188,17 @@ public abstract class StorageManagerInternal { public abstract void prepareUserStorageForMove(String fromVolumeUuid, String toVolumeUuid, List<UserInfo> users); /** * A proxy call to the corresponding method in Installer. * @see com.android.server.pm.Installer#createFsveritySetupAuthToken() */ public abstract IInstalld.IFsveritySetupAuthToken createFsveritySetupAuthToken( ParcelFileDescriptor authFd, int appUid, @UserIdInt int userId) throws IOException; /** * A proxy call to the corresponding method in Installer. * @see com.android.server.pm.Installer#enableFsverity() */ public abstract int enableFsverity(IInstalld.IFsveritySetupAuthToken authToken, String filePath, String packageName) throws IOException; }
core/java/android/security/FileIntegrityManager.java +70 −0 Original line number Diff line number Diff line Loading @@ -16,12 +16,21 @@ package android.security; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.content.Context; import android.os.IInstalld.IFsveritySetupAuthToken; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.system.ErrnoException; import com.android.internal.security.VerityUtils; import java.io.File; import java.io.IOException; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; Loading Loading @@ -54,6 +63,67 @@ public final class FileIntegrityManager { } } /** * Enables fs-verity to the owned file under the calling app's private directory. It always uses * the common configuration, i.e. SHA-256 digest algorithm, 4K block size, and without salt. * * The operation can only succeed when the file is not opened as writable by any process. * * It takes O(file size) time to build the underlying data structure for continuous * verification. The operation is atomic, i.e. it's either enabled or not, even in case of * power failure during or after the call. * * Note for the API users: When the file's authenticity is crucial, the app typical needs to * perform a signature check by itself before using the file. The signature is often delivered * as a separate file and stored next to the targeting file in the filesystem. The public key of * the signer (normally the same app developer) can be put in the APK, and the app can use the * public key to verify the signature to the file's actual fs-verity digest (from {@link * #getFsverityDigest}) before using the file. The exact format is not prescribed by the * framework. App developers may choose to use common practices like JCA for the signing and * verification, or their own preferred approach. * * @param file The file to enable fs-verity. It should be an absolute path. * * @see <a href="https://www.kernel.org/doc/html/next/filesystems/fsverity.html">Kernel doc</a> */ @FlaggedApi(Flags.FLAG_FSVERITY_API) public void setupFsverity(@NonNull File file) throws IOException { if (!file.isAbsolute()) { throw new IllegalArgumentException("Expect an absolute path"); } IFsveritySetupAuthToken authToken; // fs-verity setup requires no writable fd to the file. Make sure it's closed before // continue. try (var authFd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE)) { authToken = mService.createAuthToken(authFd); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } try { int errno = mService.setupFsverity(authToken, file.getPath(), mContext.getPackageName()); if (errno != 0) { new ErrnoException("setupFsverity", errno).rethrowAsIOException(); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns the fs-verity digest for the owned file under the calling app's * private directory, or null when the file does not have fs-verity enabled. * * @param file The file to measure the fs-verity digest. * @return The fs-verity digeset in byte[], null if none. * @see <a href="https://www.kernel.org/doc/html/next/filesystems/fsverity.html">Kernel doc</a> */ @FlaggedApi(Flags.FLAG_FSVERITY_API) public @Nullable byte[] getFsverityDigest(@NonNull File file) throws IOException { return VerityUtils.getFsverityDigest(file.getPath()); } /** * Returns whether the given certificate can be used to prove app's install source. Always * return false if the feature is not supported. Loading
core/java/android/security/IFileIntegrityService.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.security; import android.os.ParcelFileDescriptor; import android.os.IInstalld; /** * Binder interface to communicate with FileIntegrityService. * @hide Loading @@ -23,4 +26,8 @@ package android.security; interface IFileIntegrityService { boolean isApkVeritySupported(); boolean isAppSourceCertificateTrusted(in byte[] certificateBytes, in String packageName); IInstalld.IFsveritySetupAuthToken createAuthToken(in ParcelFileDescriptor authFd); int setupFsverity(IInstalld.IFsveritySetupAuthToken authToken, in String filePath, in String packageName); }
services/core/java/com/android/server/StorageManagerService.java +20 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.IInstalld.IFsveritySetupAuthToken; import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED; import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT; Loading Loading @@ -4994,5 +4995,24 @@ class StorageManagerService extends IStorageManager.Stub } } @Override public IFsveritySetupAuthToken createFsveritySetupAuthToken(ParcelFileDescriptor authFd, int appUid, @UserIdInt int userId) throws IOException { try { return mInstaller.createFsveritySetupAuthToken(authFd, appUid, userId); } catch (Installer.InstallerException e) { throw new IOException(e); } } @Override public int enableFsverity(IFsveritySetupAuthToken authToken, String filePath, String packageName) throws IOException { try { return mInstaller.enableFsverity(authToken, filePath, packageName); } catch (Installer.InstallerException e) { throw new IOException(e); } } } }