diff options
9 files changed, 109 insertions, 19 deletions
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java index 73df5e8e7b1b..5e89d06facd1 100644 --- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java +++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java @@ -421,6 +421,8 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, @NonNull private String[] mUsesStaticLibrariesSorted; + private boolean mAppMetadataFileInApk = false; + @NonNull public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath, @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp, @@ -1063,6 +1065,11 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, return memtagMode; } + @Override + public boolean isAppMetadataFileInApk() { + return mAppMetadataFileInApk; + } + @Nullable @Override public Bundle getMetaData() { @@ -2151,6 +2158,12 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, } @Override + public PackageImpl setAppMetadataFileInApk(boolean fileInApk) { + mAppMetadataFileInApk = fileInApk; + return this; + } + + @Override public PackageImpl setMetaData(@Nullable Bundle value) { metaData = value; return this; @@ -3264,6 +3277,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, dest.writeLong(this.mBooleans); dest.writeLong(this.mBooleans2); dest.writeBoolean(this.mAllowCrossUidActivitySwitchFromBelow); + dest.writeBoolean(this.mAppMetadataFileInApk); } public PackageImpl(Parcel in) { @@ -3426,6 +3440,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, this.mBooleans = in.readLong(); this.mBooleans2 = in.readLong(); this.mAllowCrossUidActivitySwitchFromBelow = in.readBoolean(); + this.mAppMetadataFileInApk = in.readBoolean(); assignDerivedFields(); assignDerivedFields2(); diff --git a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java index 66cfb69d7871..3c26a7c3eba3 100644 --- a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java +++ b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java @@ -127,4 +127,7 @@ public interface ParsedPackage extends AndroidPackage { ParsedPackage setDirectBootAware(boolean directBootAware); ParsedPackage setPersistent(boolean persistent); + + /** Retrieves whether the apk contains a app metadata file. */ + boolean isAppMetadataFileInApk(); } diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java index 5d185af17d48..5ab17a6b2b19 100644 --- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java @@ -133,6 +133,9 @@ public interface ParsingPackage { @Nullable SparseArray<int[]> splitDependencies ); + /** Sets whether the apk contains a app metadata file. */ + ParsingPackage setAppMetadataFileInApk(boolean fileInApk); + ParsingPackage setMetaData(Bundle metaData); ParsingPackage setForceQueryable(boolean forceQueryable); diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java index 2e6053d3d904..00c482722fa3 100644 --- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java @@ -46,6 +46,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.ConfigurationInfo; import android.content.pm.FeatureGroupInfo; import android.content.pm.FeatureInfo; +import android.content.pm.Flags; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.Property; @@ -163,6 +164,8 @@ public class ParsingPackageUtils { */ public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; + public static final String APP_METADATA_FILE_NAME = "app.metadata"; + /** * Path prefix for apps on expanded storage */ @@ -636,6 +639,11 @@ public class ParsingPackageUtils { pkg.setSigningDetails(SigningDetails.UNKNOWN); } + if (Flags.aslInApkAppMetadataSource() + && ArrayUtils.contains(assets.list(""), APP_METADATA_FILE_NAME)) { + pkg.setAppMetadataFileInApk(true); + } + return input.success(pkg); } catch (Exception e) { return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, @@ -686,7 +694,8 @@ public class ParsingPackageUtils { */ private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath, String codePath, Resources res, XmlResourceParser parser, int flags, - boolean shouldSkipComponents) throws XmlPullParserException, IOException { + boolean shouldSkipComponents) + throws XmlPullParserException, IOException { final String splitName; final String pkgName; diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index a1dac0456ff9..108112a4cade 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -17,6 +17,8 @@ package com.android.server.pm; import static android.content.pm.Flags.disallowSdkLibsToBeApps; +import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK; +import static android.content.pm.PackageManager.APP_METADATA_SOURCE_INSTALLER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS; @@ -43,11 +45,11 @@ import static android.os.storage.StorageManager.FLAG_STORAGE_CE; import static android.os.storage.StorageManager.FLAG_STORAGE_DE; import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL; +import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.APP_METADATA_FILE_NAME; import static com.android.server.pm.DexOptHelper.useArtService; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; -import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_NAME; import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION; import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; @@ -2207,10 +2209,16 @@ final class InstallPackageHelper { if (appMetadataFile.exists()) { ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath()); if (Flags.aslInApkAppMetadataSource()) { - ps.setAppMetadataSource(PackageManager.APP_METADATA_SOURCE_INSTALLER); + ps.setAppMetadataSource(APP_METADATA_SOURCE_INSTALLER); } } else { - ps.setAppMetadataFilePath(null); + if (Flags.aslInApkAppMetadataSource() + && parsedPackage.isAppMetadataFileInApk()) { + ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath()); + ps.setAppMetadataSource(APP_METADATA_SOURCE_APK); + } else { + ps.setAppMetadataFilePath(null); + } } } if (installRequest.getReturnCode() == PackageManager.INSTALL_SUCCEEDED) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 5792d864a8ab..6deae7790fdf 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -358,7 +358,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { /** Default byte size limit for app metadata */ private static final long DEFAULT_APP_METADATA_BYTE_SIZE_LIMIT = 32000; - private static final int APP_METADATA_FILE_ACCESS_MODE = 0640; + static final int APP_METADATA_FILE_ACCESS_MODE = 0640; /** * Throws IllegalArgumentException if the {@link IntentSender} from an immutable @@ -1782,8 +1782,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } private File getStagedAppMetadataFile() { - File file = new File(stageDir, APP_METADATA_FILE_NAME); - return file.exists() ? file : null; + return new File(stageDir, APP_METADATA_FILE_NAME); } private static boolean isAppMetadata(String name) { @@ -1799,7 +1798,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { assertCallerIsOwnerOrRoot(); synchronized (mLock) { assertPreparedAndNotCommittedOrDestroyedLocked("getAppMetadataFd"); - if (getStagedAppMetadataFile() == null) { + if (!getStagedAppMetadataFile().exists()) { return null; } try { @@ -1813,12 +1812,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void removeAppMetadata() { File file = getStagedAppMetadataFile(); - if (file != null) { + if (file.exists()) { file.delete(); } } - private static long getAppMetadataSizeLimit() { + static long getAppMetadataSizeLimit() { final long token = Binder.clearCallingIdentity(); try { return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE, @@ -2131,7 +2130,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } File appMetadataFile = getStagedAppMetadataFile(); - if (appMetadataFile != null) { + if (appMetadataFile.exists()) { long sizeLimit = getAppMetadataSizeLimit(); if (appMetadataFile.length() > sizeLimit) { appMetadataFile.delete(); @@ -3419,7 +3418,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final List<ApkLite> addedFiles = getAddedApkLitesLocked(); if (addedFiles.isEmpty() - && (removeSplitList.size() == 0 || getStagedAppMetadataFile() != null)) { + && (removeSplitList.size() == 0 || getStagedAppMetadataFile().exists())) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, TextUtils.formatSimple("Session: %d. No packages staged in %s", sessionId, stageDir.getAbsolutePath())); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index dadafd7f9438..380de56b5c19 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -18,6 +18,8 @@ package com.android.server.pm; import static android.Manifest.permission.MANAGE_DEVICE_ADMINS; import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS; import static android.app.AppOpsManager.MODE_IGNORED; +import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK; +import static android.content.pm.PackageManager.APP_METADATA_SOURCE_UNKNOWN; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; @@ -596,7 +598,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService static final String RANDOM_DIR_PREFIX = "~~"; static final char RANDOM_CODEPATH_PREFIX = '-'; - static final String APP_METADATA_FILE_NAME = "app.metadata"; + public static final String APP_METADATA_FILE_NAME = "app.metadata"; + public static final String APP_METADATA_FILE_IN_APK_PATH = "assets/" + APP_METADATA_FILE_NAME; static final int DEFAULT_FILE_ACCESS_MODE = 0644; @@ -5230,15 +5233,30 @@ public class PackageManagerService implements PackageSender, TestUtilityService new PackageManager.NameNotFoundException(packageName)); } String filePath = ps.getAppMetadataFilePath(); - if (filePath != null) { - File file = new File(filePath); - try { - return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); - } catch (FileNotFoundException e) { + if (filePath == null) { + return null; + } + File file = new File(filePath); + if (Flags.aslInApkAppMetadataSource() && !file.exists() + && ps.getAppMetadataSource() == APP_METADATA_SOURCE_APK) { + String apkPath = ps.getPkg().getSplits().get(0).getPath(); + if (!PackageManagerServiceUtils.extractAppMetadataFromApk(apkPath, file)) { + if (file.exists()) { + file.delete(); + } + synchronized (mLock) { + PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); + pkgSetting.setAppMetadataFilePath(null); + pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_UNKNOWN); + } return null; } } - return null; + try { + return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); + } catch (FileNotFoundException e) { + return null; + } } @android.annotation.EnforcePermission(android.Manifest.permission.GET_APP_METADATA) diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 4f9ed03dc8e7..eb9035dba038 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -27,6 +27,9 @@ import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME; import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH; import static com.android.server.LocalManagerRegistry.ManagerNotFoundException; +import static com.android.server.pm.PackageInstallerSession.APP_METADATA_FILE_ACCESS_MODE; +import static com.android.server.pm.PackageInstallerSession.getAppMetadataSizeLimit; +import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_IN_APK_PATH; import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION; import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION; import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING; @@ -142,6 +145,8 @@ import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.zip.GZIPInputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; /** * Class containing helper methods for the PackageManagerService. @@ -1556,6 +1561,35 @@ public class PackageManagerServiceUtils { return initiatingPackageName == null || SHELL_PACKAGE_NAME.equals(initiatingPackageName); } + /** + * Extract the app.metadata file from apk. + */ + public static boolean extractAppMetadataFromApk(String apkPath, File appMetadataFile) { + boolean found = false; + try (ZipInputStream zipInputStream = + new ZipInputStream(new FileInputStream(new File(apkPath)))) { + ZipEntry zipEntry = null; + while ((zipEntry = zipInputStream.getNextEntry()) != null) { + if (zipEntry.getName().equals(APP_METADATA_FILE_IN_APK_PATH)) { + found = true; + try (FileOutputStream out = new FileOutputStream(appMetadataFile)) { + FileUtils.copy(zipInputStream, out); + } + if (appMetadataFile.length() > getAppMetadataSizeLimit()) { + appMetadataFile.delete(); + return false; + } + Os.chmod(appMetadataFile.getAbsolutePath(), APP_METADATA_FILE_ACCESS_MODE); + break; + } + } + } catch (Exception e) { + Slog.e(TAG, e.getMessage()); + return false; + } + return found; + } + public static void linkFilesToOldDirs(@NonNull Installer installer, @NonNull String packageName, @NonNull File newPath, diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt index d4b57f191ecd..96e9ca0c19b5 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt @@ -275,6 +275,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag AndroidPackage::isUpdatableSystem, AndroidPackage::getEmergencyInstaller, AndroidPackage::isAllowCrossUidActivitySwitchFromBelow, + PackageImpl::isAppMetadataFileInApk, ) override fun extraParams() = listOf( |