Merge "Fail install when resources.arsc is compressed" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b8a61d13c2
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user