Merge "Fail install when resources.arsc is compressed" into rvc-dev

This commit is contained in:
Ryan Mitchell
2020-04-13 14:57:19 +00:00
committed by Android (Google) Code Review
8 changed files with 74 additions and 7 deletions

View File

@@ -1550,6 +1550,16 @@ public abstract class PackageManager {
*/
public static final int INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED = -123;
/**
* Installation failed return code: the {@code resources.arsc} of one of the APKs being
* installed is compressed or not aligned on a 4-byte boundary. Resource tables that cannot be
* memory mapped exert excess memory pressure on the system and drastically slow down
* construction of {@link Resources} objects.
*
* @hide
*/
public static final int INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED = -124;
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,

View File

@@ -22,6 +22,7 @@ import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
import static android.os.Build.VERSION_CODES.DONUT;
import static android.os.Build.VERSION_CODES.O;
@@ -344,7 +345,20 @@ public class ParsingPackageUtils {
+ result.getErrorMessage());
}
ParsingPackage pkg = result.getResult();
final ParsingPackage pkg = result.getResult();
if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.R
&& assets.containsAllocatedTable()) {
final ParseResult<?> deferResult = input.deferError(
"Targeting R+ (version" + Build.VERSION_CODES.R + " and above) requires the"
+ " resources.arsc of installed APKs to be stored uncompressed and"
+ " aligned on a 4-byte boundary",
DeferredError.RESOURCES_ARSC_COMPRESSED);
if (deferResult.isError()) {
return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,
deferResult.getErrorMessage());
}
}
ApkAssets apkAssets = assets.getApkAssets()[0];
if (apkAssets.definesOverlayable()) {
SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();

View File

@@ -59,6 +59,16 @@ public interface ParseInput {
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
public static final long EMPTY_INTENT_ACTION_CATEGORY = 151163173;
/**
* The {@code resources.arsc} of one of the APKs being installed is compressed or not
* aligned on a 4-byte boundary. Resource tables that cannot be memory mapped exert excess
* memory pressure on the system and drastically slow down construction of
* {@link android.content.res.Resources} objects.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
public static final long RESOURCES_ARSC_COMPRESSED = 132742131;
}
<ResultType> ParseResult<ResultType> success(ResultType result);

View File

@@ -819,6 +819,19 @@ public final class AssetManager implements AutoCloseable {
}
}
/**
* Returns whether the {@code resources.arsc} of any loaded apk assets is allocated in RAM
* (not mmapped).
*
* @hide
*/
public boolean containsAllocatedTable() {
synchronized (this) {
ensureValidLocked();
return nativeContainsAllocatedTable(mObject);
}
}
CharSequence getPooledStringForCookie(int cookie, int id) {
// Cookies map to ApkAssets starting at 1.
return getApkAssets()[cookie - 1].getStringFromPool(id);
@@ -1482,6 +1495,7 @@ public final class AssetManager implements AutoCloseable {
long ptr, boolean includeOverlays, boolean includeLoaders);
// File native methods.
private static native boolean nativeContainsAllocatedTable(long ptr);
private static native @Nullable String[] nativeList(long ptr, @NonNull String path)
throws IOException;
private static native long nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode);

View File

@@ -481,6 +481,11 @@ static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/
return sparse_array;
}
static jboolean ContainsAllocatedTable(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
return assetmanager->ContainsAllocatedTable();
}
static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
ScopedUtfChars path_utf8(env, path);
if (path_utf8.c_str() == nullptr) {
@@ -1495,6 +1500,7 @@ static const JNINativeMethod gAssetManagerMethods[] = {
(void*)NativeGetAssignedPackageIdentifiers},
// AssetManager file methods.
{"nativeContainsAllocatedTable", "(J)Z", (void*)ContainsAllocatedTable},
{"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
{"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
{"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",

View File

@@ -331,6 +331,11 @@ bool AssetManager2::GetOverlayablesToString(const android::StringPiece& package_
return true;
}
bool AssetManager2::ContainsAllocatedTable() const {
return std::find_if(apk_assets_.begin(), apk_assets_.end(),
std::mem_fn(&ApkAssets::IsTableAllocated)) != apk_assets_.end();
}
void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
const int diff = configuration_.diff(configuration);
configuration_ = configuration;

View File

@@ -119,31 +119,36 @@ class ApkAssets {
package_property_t flags = 0U,
std::unique_ptr<const AssetsProvider> override_asset = nullptr);
inline const std::string& GetPath() const {
const std::string& GetPath() const {
return path_;
}
inline const AssetsProvider* GetAssetsProvider() const {
const AssetsProvider* GetAssetsProvider() const {
return assets_provider_.get();
}
// This is never nullptr.
inline const LoadedArsc* GetLoadedArsc() const {
const LoadedArsc* GetLoadedArsc() const {
return loaded_arsc_.get();
}
inline const LoadedIdmap* GetLoadedIdmap() const {
const LoadedIdmap* GetLoadedIdmap() const {
return loaded_idmap_.get();
}
inline bool IsLoader() const {
bool IsLoader() const {
return (property_flags_ & PROPERTY_LOADER) != 0;
}
inline bool IsOverlay() const {
bool IsOverlay() const {
return loaded_idmap_ != nullptr;
}
// Returns whether the resources.arsc is allocated in RAM (not mmapped).
bool IsTableAllocated() const {
return resources_asset_ && resources_asset_->isAllocated();
}
bool IsUpToDate() const;
// Creates an Asset from a file on disk.

View File

@@ -134,6 +134,9 @@ class AssetManager2 {
const std::unordered_map<std::string, std::string>*
GetOverlayableMapForPackage(uint32_t package_id) const;
// Returns whether the resources.arsc of any loaded apk assets is allocated in RAM (not mmapped).
bool ContainsAllocatedTable() const;
// Sets/resets the configuration for this AssetManager. This will cause all
// caches that are related to the configuration change to be invalidated.
void SetConfiguration(const ResTable_config& configuration);