Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -693,6 +693,7 @@ java_defaults { ], static_libs: [ "apex_aidl_interface-java", "framework-protos", "mediaplayer2-protos", "android.hidl.base-V1.0-java", Loading core/java/android/content/pm/PackageManager.java +8 −0 Original line number Diff line number Diff line Loading @@ -855,6 +855,14 @@ public abstract class PackageManager { */ public static final int INSTALL_VIRTUAL_PRELOAD = 0x00010000; /** * Flag parameter for {@link #installPackage} to indicate that this package * is an APEX package * * @hide */ public static final int INSTALL_APEX = 0x00020000; /** @hide */ @IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = { DONT_KILL_APP Loading services/core/java/com/android/server/pm/PackageInstallerService.java +2 −3 Original line number Diff line number Diff line Loading @@ -58,7 +58,6 @@ import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SELinux; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; Loading Loading @@ -646,8 +645,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } try { Os.mkdir(stageDir.getAbsolutePath(), 0755); Os.chmod(stageDir.getAbsolutePath(), 0755); Os.mkdir(stageDir.getAbsolutePath(), 0775); Os.chmod(stageDir.getAbsolutePath(), 0775); } catch (ErrnoException e) { // This purposefully throws if directory already exists throw new IOException("Failed to prepare session dir: " + stageDir, e); Loading services/core/java/com/android/server/pm/PackageInstallerSession.java +87 −6 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import static com.android.server.pm.PackageInstallerService.prepareStageDir; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.apex.IApexService; import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; Loading Loading @@ -75,6 +76,7 @@ import android.os.ParcelableException; import android.os.Process; import android.os.RemoteException; import android.os.RevocableFileDescriptor; import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.storage.StorageManager; Loading Loading @@ -838,12 +840,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { resolveStageDirLocked(); mSealed = true; try { if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { validateApexInstallLocked(pkgInfo); } else { // Verify that stage looks sane with respect to existing application. // This currently only ensures packageName, versionCode, and certificate // consistency. try { validateInstallLocked(pkgInfo); validateApkInstallLocked(pkgInfo); } } catch (PackageManagerException e) { throw e; } catch (Throwable e) { Loading Loading @@ -926,6 +931,31 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Preconditions.checkNotNull(mSigningDetails); Preconditions.checkNotNull(mResolvedBaseFile); if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { commitApexLocked(); } else { commitApkLocked(); } } @GuardedBy("mLock") private void commitApexLocked() throws PackageManagerException { try { IApexService apex = IApexService.Stub.asInterface( ServiceManager.getService("apexservice")); apex.installPackage(mResolvedBaseFile.toString()); } catch (Throwable e) { // Convert all exceptions into package manager exceptions as only those are handled // in the code above throw new PackageManagerException(e); } finally { destroyInternal(); dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "APEX installed", null); } } @GuardedBy("mLock") private void commitApkLocked() throws PackageManagerException { if (needToAskForPermissionsLocked()) { // User needs to confirm installation; give installer an intent they can use to involve // user. Loading Loading @@ -1047,6 +1077,57 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { (params.installFlags & PackageManager.DONT_KILL_APP) != 0; } @GuardedBy("mLock") private void validateApexInstallLocked(@Nullable PackageInfo pkgInfo) throws PackageManagerException { mResolvedStagedFiles.clear(); mResolvedInheritedFiles.clear(); try { resolveStageDirLocked(); } catch (IOException e) { throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR, "Failed to resolve stage location", e); } final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter); if (ArrayUtils.isEmpty(addedFiles)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged"); } if (addedFiles.length > 1) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Only one APEX file at a time might be installed"); } File addedFile = addedFiles[0]; final ApkLite apk; try { apk = PackageParser.parseApkLite( addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES); } catch (PackageParserException e) { throw PackageManagerException.from(e); } mPackageName = apk.packageName; mVersionCode = apk.getLongVersionCode(); mSigningDetails = apk.signingDetails; mResolvedBaseFile = addedFile; assertApkConsistentLocked(String.valueOf(addedFile), apk); if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) { try { // STOPSHIP: For APEX we should also implement proper APK Signature verification. mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts( pkgInfo.applicationInfo.sourceDir, PackageParser.SigningDetails.SignatureSchemeVersion.JAR); } catch (PackageParserException e) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Couldn't obtain signatures from base APK"); } } } /** * Validate install by confirming that all application packages are have * consistent package name, version code, and signing certificates. Loading @@ -1060,7 +1141,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * {@link PackageManagerService}. */ @GuardedBy("mLock") private void validateInstallLocked(@Nullable PackageInfo pkgInfo) private void validateApkInstallLocked(@Nullable PackageInfo pkgInfo) throws PackageManagerException { ApkLite baseApk = null; mPackageName = null; Loading services/core/java/com/android/server/pm/PackageManagerShellCommand.java +7 −1 Original line number Diff line number Diff line Loading @@ -920,7 +920,10 @@ class PackageManagerShellCommand extends ShellCommand { pw.println("Error: must either specify a package size or an APK file"); return 1; } if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk", final boolean isApex = (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0; String splitName = "base." + (isApex ? "apex" : "apk"); if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName, false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { return 1; } Loading Loading @@ -2262,6 +2265,9 @@ class PackageManagerShellCommand extends ShellCommand { case "--force-sdk": sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK; break; case "--apex": sessionParams.installFlags |= PackageManager.INSTALL_APEX; break; default: throw new IllegalArgumentException("Unknown option " + opt); } Loading Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -693,6 +693,7 @@ java_defaults { ], static_libs: [ "apex_aidl_interface-java", "framework-protos", "mediaplayer2-protos", "android.hidl.base-V1.0-java", Loading
core/java/android/content/pm/PackageManager.java +8 −0 Original line number Diff line number Diff line Loading @@ -855,6 +855,14 @@ public abstract class PackageManager { */ public static final int INSTALL_VIRTUAL_PRELOAD = 0x00010000; /** * Flag parameter for {@link #installPackage} to indicate that this package * is an APEX package * * @hide */ public static final int INSTALL_APEX = 0x00020000; /** @hide */ @IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = { DONT_KILL_APP Loading
services/core/java/com/android/server/pm/PackageInstallerService.java +2 −3 Original line number Diff line number Diff line Loading @@ -58,7 +58,6 @@ import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SELinux; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; Loading Loading @@ -646,8 +645,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } try { Os.mkdir(stageDir.getAbsolutePath(), 0755); Os.chmod(stageDir.getAbsolutePath(), 0755); Os.mkdir(stageDir.getAbsolutePath(), 0775); Os.chmod(stageDir.getAbsolutePath(), 0775); } catch (ErrnoException e) { // This purposefully throws if directory already exists throw new IOException("Failed to prepare session dir: " + stageDir, e); Loading
services/core/java/com/android/server/pm/PackageInstallerSession.java +87 −6 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import static com.android.server.pm.PackageInstallerService.prepareStageDir; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.apex.IApexService; import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; Loading Loading @@ -75,6 +76,7 @@ import android.os.ParcelableException; import android.os.Process; import android.os.RemoteException; import android.os.RevocableFileDescriptor; import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.storage.StorageManager; Loading Loading @@ -838,12 +840,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { resolveStageDirLocked(); mSealed = true; try { if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { validateApexInstallLocked(pkgInfo); } else { // Verify that stage looks sane with respect to existing application. // This currently only ensures packageName, versionCode, and certificate // consistency. try { validateInstallLocked(pkgInfo); validateApkInstallLocked(pkgInfo); } } catch (PackageManagerException e) { throw e; } catch (Throwable e) { Loading Loading @@ -926,6 +931,31 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Preconditions.checkNotNull(mSigningDetails); Preconditions.checkNotNull(mResolvedBaseFile); if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { commitApexLocked(); } else { commitApkLocked(); } } @GuardedBy("mLock") private void commitApexLocked() throws PackageManagerException { try { IApexService apex = IApexService.Stub.asInterface( ServiceManager.getService("apexservice")); apex.installPackage(mResolvedBaseFile.toString()); } catch (Throwable e) { // Convert all exceptions into package manager exceptions as only those are handled // in the code above throw new PackageManagerException(e); } finally { destroyInternal(); dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "APEX installed", null); } } @GuardedBy("mLock") private void commitApkLocked() throws PackageManagerException { if (needToAskForPermissionsLocked()) { // User needs to confirm installation; give installer an intent they can use to involve // user. Loading Loading @@ -1047,6 +1077,57 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { (params.installFlags & PackageManager.DONT_KILL_APP) != 0; } @GuardedBy("mLock") private void validateApexInstallLocked(@Nullable PackageInfo pkgInfo) throws PackageManagerException { mResolvedStagedFiles.clear(); mResolvedInheritedFiles.clear(); try { resolveStageDirLocked(); } catch (IOException e) { throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR, "Failed to resolve stage location", e); } final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter); if (ArrayUtils.isEmpty(addedFiles)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged"); } if (addedFiles.length > 1) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Only one APEX file at a time might be installed"); } File addedFile = addedFiles[0]; final ApkLite apk; try { apk = PackageParser.parseApkLite( addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES); } catch (PackageParserException e) { throw PackageManagerException.from(e); } mPackageName = apk.packageName; mVersionCode = apk.getLongVersionCode(); mSigningDetails = apk.signingDetails; mResolvedBaseFile = addedFile; assertApkConsistentLocked(String.valueOf(addedFile), apk); if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) { try { // STOPSHIP: For APEX we should also implement proper APK Signature verification. mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts( pkgInfo.applicationInfo.sourceDir, PackageParser.SigningDetails.SignatureSchemeVersion.JAR); } catch (PackageParserException e) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Couldn't obtain signatures from base APK"); } } } /** * Validate install by confirming that all application packages are have * consistent package name, version code, and signing certificates. Loading @@ -1060,7 +1141,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * {@link PackageManagerService}. */ @GuardedBy("mLock") private void validateInstallLocked(@Nullable PackageInfo pkgInfo) private void validateApkInstallLocked(@Nullable PackageInfo pkgInfo) throws PackageManagerException { ApkLite baseApk = null; mPackageName = null; Loading
services/core/java/com/android/server/pm/PackageManagerShellCommand.java +7 −1 Original line number Diff line number Diff line Loading @@ -920,7 +920,10 @@ class PackageManagerShellCommand extends ShellCommand { pw.println("Error: must either specify a package size or an APK file"); return 1; } if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk", final boolean isApex = (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0; String splitName = "base." + (isApex ? "apex" : "apk"); if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName, false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { return 1; } Loading Loading @@ -2262,6 +2265,9 @@ class PackageManagerShellCommand extends ShellCommand { case "--force-sdk": sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK; break; case "--apex": sessionParams.installFlags |= PackageManager.INSTALL_APEX; break; default: throw new IllegalArgumentException("Unknown option " + opt); } Loading