summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kalesh Singh <kaleshsingh@google.com> 2024-08-30 22:42:34 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2024-08-30 22:42:34 +0000
commit56b9afac53e4355da3123ba869573857e28909c5 (patch)
treebb43b5395481020353e16a88d233e33236725f95
parent34eacbbf0590eec300d156afd5eb82fd4b1a81bb (diff)
parent8565fedcf838e731b7ce651a02045efe3ac1db82 (diff)
Merge changes I30a1bc50,Ifc785251 into main
* changes: PackageManager: 16K: Extract native libs that are not zipaligned correctly PackageManager: Factor out extractNativeLibFromApk()
-rw-r--r--core/jni/com_android_internal_content_NativeLibraryHelper.cpp168
1 files changed, 101 insertions, 67 deletions
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index fba0d81d431f..7ad18b83f0d6 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "NativeLibraryHelper"
//#define LOG_NDEBUG 0
+#include <android-base/properties.h>
#include <androidfw/ApkParsing.h>
#include <androidfw/ZipFileRO.h>
#include <androidfw/ZipUtils.h>
@@ -36,6 +37,7 @@
#include <zlib.h>
#include <memory>
+#include <string>
#include "com_android_internal_content_FileSystemUtils.h"
#include "core_jni_helpers.h"
@@ -125,72 +127,10 @@ sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char
return INSTALL_SUCCEEDED;
}
-/*
- * Copy the native library if needed.
- *
- * This function assumes the library and path names passed in are considered safe.
- */
-static install_status_t
-copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
-{
- static const size_t kPageSize = getpagesize();
- void** args = reinterpret_cast<void**>(arg);
- jstring* javaNativeLibPath = (jstring*) args[0];
- jboolean extractNativeLibs = *(jboolean*) args[1];
- jboolean debuggable = *(jboolean*) args[2];
-
- ScopedUtfChars nativeLibPath(env, *javaNativeLibPath);
-
- uint32_t uncompLen;
- uint32_t when;
- uint32_t crc;
-
- uint16_t method;
- off64_t offset;
- uint16_t extraFieldLength;
- if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, nullptr, &offset, &when, &crc,
- &extraFieldLength)) {
- ALOGE("Couldn't read zip entry info\n");
- return INSTALL_FAILED_INVALID_APK;
- }
-
- // Always extract wrap.sh for debuggable, even if extractNativeLibs=false. This makes it
- // easier to use wrap.sh because it only works when it is extracted, see
- // frameworks/base/services/core/java/com/android/server/am/ProcessList.java.
- bool forceExtractCurrentFile = debuggable && strcmp(fileName, "wrap.sh") == 0;
-
- if (!extractNativeLibs && !forceExtractCurrentFile) {
- // check if library is uncompressed and page-aligned
- if (method != ZipFileRO::kCompressStored) {
- ALOGE("Library '%s' is compressed - will not be able to open it directly from apk.\n",
- fileName);
- return INSTALL_FAILED_INVALID_APK;
- }
-
- if (offset % kPageSize != 0) {
- ALOGE("Library '%s' is not PAGE(%zu)-aligned - will not be able to open it directly "
- "from apk.\n", fileName, kPageSize);
- return INSTALL_FAILED_INVALID_APK;
- }
-
-#ifdef ENABLE_PUNCH_HOLES
- // if library is uncompressed, punch hole in it in place
- if (!punchHolesInElf64(zipFile->getZipFileName(), offset)) {
- ALOGW("Failed to punch uncompressed elf file :%s inside apk : %s at offset: "
- "%" PRIu64 "",
- fileName, zipFile->getZipFileName(), offset);
- }
-
- // if extra field for this zip file is present with some length, possibility is that it is
- // padding added for zip alignment. Punch holes there too.
- if (!punchHolesInZip(zipFile->getZipFileName(), offset, extraFieldLength)) {
- ALOGW("Failed to punch apk : %s at extra field", zipFile->getZipFileName());
- }
-#endif // ENABLE_PUNCH_HOLES
-
- return INSTALL_SUCCEEDED;
- }
-
+static install_status_t extractNativeLibFromApk(ZipFileRO* zipFile, ZipEntryRO zipEntry,
+ const char* fileName,
+ const std::string nativeLibPath, uint32_t when,
+ uint32_t uncompLen, uint32_t crc) {
// Build local file path
const size_t fileNameLen = strlen(fileName);
char localFileName[nativeLibPath.size() + fileNameLen + 2];
@@ -313,6 +253,88 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
}
/*
+ * Copy the native library if needed.
+ *
+ * This function assumes the library and path names passed in are considered safe.
+ */
+static install_status_t copyFileIfChanged(JNIEnv* env, void* arg, ZipFileRO* zipFile,
+ ZipEntryRO zipEntry, const char* fileName) {
+ static const size_t kPageSize = getpagesize();
+ void** args = reinterpret_cast<void**>(arg);
+ jstring* javaNativeLibPath = (jstring*)args[0];
+ jboolean extractNativeLibs = *(jboolean*)args[1];
+ jboolean debuggable = *(jboolean*)args[2];
+ jboolean app_compat_16kb = *(jboolean*)args[3];
+ install_status_t ret = INSTALL_SUCCEEDED;
+
+ ScopedUtfChars nativeLibPath(env, *javaNativeLibPath);
+
+ uint32_t uncompLen;
+ uint32_t when;
+ uint32_t crc;
+
+ uint16_t method;
+ off64_t offset;
+ uint16_t extraFieldLength;
+ if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, nullptr, &offset, &when, &crc,
+ &extraFieldLength)) {
+ ALOGE("Couldn't read zip entry info\n");
+ return INSTALL_FAILED_INVALID_APK;
+ }
+
+ // Always extract wrap.sh for debuggable, even if extractNativeLibs=false. This makes it
+ // easier to use wrap.sh because it only works when it is extracted, see
+ // frameworks/base/services/core/java/com/android/server/am/ProcessList.java.
+ bool forceExtractCurrentFile = debuggable && strcmp(fileName, "wrap.sh") == 0;
+
+ if (!extractNativeLibs && !forceExtractCurrentFile) {
+ // check if library is uncompressed and page-aligned
+ if (method != ZipFileRO::kCompressStored) {
+ ALOGE("Library '%s' is compressed - will not be able to open it directly from apk.\n",
+ fileName);
+ return INSTALL_FAILED_INVALID_APK;
+ }
+
+ if (offset % kPageSize != 0) {
+ // If the library is zip-aligned correctly for 4kb devices and app compat is
+ // enabled, on 16kb devices fallback to extraction
+ if (offset % 0x1000 == 0 && app_compat_16kb) {
+ ALOGI("16kB AppCompat: Library '%s' is not PAGE(%zu)-aligned - falling back to "
+ "extraction from apk\n",
+ fileName, kPageSize);
+ return extractNativeLibFromApk(zipFile, zipEntry, fileName, nativeLibPath.c_str(),
+ when, uncompLen, crc);
+ }
+
+ ALOGE("Library '%s' is not PAGE(%zu)-aligned - will not be able to open it directly "
+ "from apk.\n",
+ fileName, kPageSize);
+ return INSTALL_FAILED_INVALID_APK;
+ }
+
+#ifdef ENABLE_PUNCH_HOLES
+ // if library is uncompressed, punch hole in it in place
+ if (!punchHolesInElf64(zipFile->getZipFileName(), offset)) {
+ ALOGW("Failed to punch uncompressed elf file :%s inside apk : %s at offset: "
+ "%" PRIu64 "",
+ fileName, zipFile->getZipFileName(), offset);
+ }
+
+ // if extra field for this zip file is present with some length, possibility is that it is
+ // padding added for zip alignment. Punch holes there too.
+ if (!punchHolesInZip(zipFile->getZipFileName(), offset, extraFieldLength)) {
+ ALOGW("Failed to punch apk : %s at extra field", zipFile->getZipFileName());
+ }
+#endif // ENABLE_PUNCH_HOLES
+
+ return INSTALL_SUCCEEDED;
+ }
+
+ return extractNativeLibFromApk(zipFile, zipEntry, fileName, nativeLibPath.c_str(), when,
+ uncompLen, crc);
+}
+
+/*
* An iterator over all shared libraries in a zip file. An entry is
* considered to be a shared library if all of the conditions below are
* satisfied :
@@ -498,12 +520,24 @@ static int findSupportedAbi(JNIEnv* env, jlong apkHandle, jobjectArray supported
return status;
}
+static inline bool app_compat_16kb_enabled() {
+ static const size_t kPageSize = getpagesize();
+
+ // App compat is only applicable on 16kb-page-size devices.
+ if (kPageSize != 0x4000) {
+ return false;
+ }
+
+ return android::base::GetBoolProperty("bionic.linker.16kb.app_compat.enabled", false);
+}
+
static jint
com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz,
jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi,
jboolean extractNativeLibs, jboolean debuggable)
{
- void* args[] = { &javaNativeLibPath, &extractNativeLibs, &debuggable };
+ jboolean app_compat_16kb = app_compat_16kb_enabled();
+ void* args[] = { &javaNativeLibPath, &extractNativeLibs, &debuggable, &app_compat_16kb };
return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi, debuggable,
copyFileIfChanged, reinterpret_cast<void*>(args));
}