OSDN Git Service

Package Manager :optimization forZipFileRO->NextEntry
authorShuo Gao <shuo.gao@intel.com>
Sat, 10 Oct 2015 07:59:07 +0000 (15:59 +0800)
committerChih-Wei Huang <cwhuang@linux.org.tw>
Wed, 20 Jul 2016 09:53:19 +0000 (17:53 +0800)
In functions like findSurpportedAbi and CopyNativeLibraries, it using
ZipFileRO->NextEntry to get FileName of each file in package, and then find a
best ABI or do CRC checking for native libraries.

But in current implementation, NextEntry will read info from both CentralDirectoryRecord
and LocalFileHeader, to compare the filename, signature and so on to check the integrity.

But on platform that has bad "read" performance like Sofia 3GR, it cost too much
time reading infor from LocalFileHeader in each NextEntry, lead to so much time
scanning one package that contains dozens of binaries.

So add the NextEntryNoIntegrity API for such processing that just need a filename, like
use case mentioned above. But it might not trustable if package damaged or changed
unpredictable.

Change-Id: I1647b94f75edf2476f13c1b91edc3a398521928d
Tracked-On: https://jira01.devtools.intel.com/browse/OAM-5845
Depends-Change-Id:Ib06f9486fc2c0f26694018acdb5640d5e650b4e0
Signed-off-by: Shuo Gao <shuo.gao@intel.com>
Signed-off-by: Johnson Z Wu <johnson.z.wu@intel.com>
Signed-off-by: taozha2x <taox.z.zhang@intel.com>
Reviewed-on: https://android.intel.com:443/426686

core/jni/Android.mk
core/jni/com_android_internal_content_NativeLibraryHelper.cpp
include/androidfw/ZipFileRO.h
libs/androidfw/Android.mk
libs/androidfw/ZipFileRO.cpp

index fc15b96..86c1918 100644 (file)
@@ -28,6 +28,10 @@ LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
 LOCAL_CFLAGS += -DU_USING_ICU_NAMESPACE=0
 
+ifeq ($(ZIP_OPTIMIZATION_NO_INTEGRITY),true)
+    LOCAL_CFLAGS += -DZIP_NO_INTEGRITY
+endif
+
 LOCAL_SRC_FILES:= \
     AndroidRuntime.cpp \
     com_android_internal_content_NativeLibraryHelper.cpp \
index daa6f82..cccd318 100644 (file)
@@ -68,7 +68,11 @@ enum install_status_t {
     NO_NATIVE_LIBRARIES = -114
 };
 
-typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*);
+typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*
+#ifdef ZIP_NO_INTEGRITY
+, const char*
+#endif
+);
 
 // Equivalent to android.os.FileUtils.isFilenameSafe
 static bool
@@ -138,6 +142,9 @@ isFileDifferent(const char* filePath, uint32_t fileSize, time_t modifiedTime,
     uLong crc = crc32(0L, Z_NULL, 0);
     unsigned char crcBuffer[16384];
     ssize_t numBytes;
+#ifdef ZIP_NO_INTEGRITY
+    posix_fadvise64(fd, 0, fileSize, POSIX_FADV_WILLNEED);
+#endif
     while ((numBytes = TEMP_FAILURE_RETRY(read(fd, crcBuffer, sizeof(crcBuffer)))) > 0) {
         crc = crc32(crc, crcBuffer, numBytes);
     }
@@ -153,7 +160,11 @@ isFileDifferent(const char* filePath, uint32_t fileSize, time_t modifiedTime,
 }
 
 static install_status_t
-sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char*)
+sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char*
+#ifdef ZIP_NO_INTEGRITY
+, const char*
+#endif
+)
 {
     size_t* total = (size_t*) arg;
     uint32_t uncompLen;
@@ -173,7 +184,11 @@ sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char
  * 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)
+copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName
+#ifdef ZIP_NO_INTEGRITY
+, const char* entryName
+#endif
+)
 {
     void** args = reinterpret_cast<void**>(arg);
     jstring* javaNativeLibPath = (jstring*) args[0];
@@ -239,6 +254,13 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
         return INSTALL_SUCCEEDED;
     }
 
+#ifdef ZIP_NO_INTEGRITY
+    // do integrity check for the current entry
+    if ((zipEntry = zipFile->findEntryByName(entryName)) == NULL) {
+        ALOGD("Couldn't pass integrity check for library");
+        return INSTALL_FAILED_INTERNAL_ERROR;
+    }
+#endif
     char localTmpFileName[nativeLibPath.size() + TMP_FILE_PATTERN_LEN + 2];
     if (strlcpy(localTmpFileName, nativeLibPath.c_str(), sizeof(localTmpFileName))
             != nativeLibPath.size()) {
@@ -329,6 +351,55 @@ public:
         return new NativeLibrariesIterator(zipFile, cookie);
     }
 
+#ifdef ZIP_NO_INTEGRITY
+    ZipEntryRO nextNoIntegrity() {
+        ZipEntryRO next = NULL;
+        while ((next = mZipFile->nextEntryNoIntegrity(mCookie)) != NULL) {
+            // Make sure this entry has a filename.
+            if (mZipFile->getEntryFileName(next, fileName, sizeof(fileName))) {
+                continue;
+            }
+
+            // Make sure we're in the lib directory of the ZIP.
+            if (strncmp(fileName, APK_LIB, APK_LIB_LEN)) {
+                continue;
+            }
+
+            // Make sure the filename is at least to the minimum library name size.
+            const size_t fileNameLen = strlen(fileName);
+            static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN;
+            if (fileNameLen < minLength) {
+                continue;
+            }
+
+            const char* lastSlash = strrchr(fileName, '/');
+            ALOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName);
+
+            // Exception: If we find the gdbserver binary, return it.
+            if (!strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
+                mLastSlash = lastSlash;
+                break;
+            }
+
+            // Make sure the filename starts with lib and ends with ".so".
+            if (strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN)
+                || strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)) {
+                continue;
+            }
+
+            // Make sure the filename is safe.
+            if (!isFilenameSafe(lastSlash + 1)) {
+                continue;
+            }
+
+            mLastSlash = lastSlash;
+            break;
+        }
+
+        return next;
+    }
+#endif
+
     ZipEntryRO next() {
         ZipEntryRO next = NULL;
         while ((next = mZipFile->nextEntry(mCookie)) != NULL) {
@@ -410,7 +481,11 @@ iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi,
         return INSTALL_FAILED_INVALID_APK;
     }
     ZipEntryRO entry = NULL;
+#ifdef ZIP_NO_INTEGRITY
+    while ((entry = it->nextNoIntegrity()) != NULL) {
+#else
     while ((entry = it->next()) != NULL) {
+#endif
         const char* fileName = it->currentEntry();
         const char* lastSlash = it->lastSlash();
 
@@ -419,8 +494,11 @@ iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi,
         const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset;
 
         if (cpuAbi.size() == cpuAbiRegionSize && !strncmp(cpuAbiOffset, cpuAbi.c_str(), cpuAbiRegionSize)) {
-            install_status_t ret = callFunc(env, callArg, zipFile, entry, lastSlash + 1);
-
+            install_status_t ret = callFunc(env, callArg, zipFile, entry, lastSlash + 1
+#ifdef ZIP_NO_INTEGRITY
+               , fileName
+#endif
+               );
             if (ret != INSTALL_SUCCEEDED) {
                 ALOGV("Failure for entry %s", lastSlash + 1);
                 return ret;
@@ -453,7 +531,11 @@ static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supported
 
     ZipEntryRO entry = NULL;
     int status = NO_NATIVE_LIBRARIES;
+#ifdef ZIP_NO_INTEGRITY
+    while ((entry = it->nextNoIntegrity()) != NULL) {
+#else
     while ((entry = it->next()) != NULL) {
+#endif
         // We're currently in the lib/ directory of the APK, so it does have some native
         // code. We should return INSTALL_FAILED_NO_MATCHING_ABIS if none of the
         // libraries match.
index 7680342..1965ffd 100644 (file)
@@ -99,6 +99,14 @@ public:
      */
     ZipEntryRO nextEntry(void* cookie);
 
+#ifdef ZIP_NO_INTEGRITY
+    /**
+     * Return the next entry in iteration order, or NULL if there are no more
+     * entries in this archive, just from RDS without integrity check.
+     */
+    ZipEntryRO nextEntryNoIntegrity(void* cookie);
+#endif
+
     void endIteration(void* cookie);
 
     void releaseEntry(ZipEntryRO entry) const;
index 2f28700..91e3e9d 100644 (file)
@@ -46,6 +46,9 @@ LOCAL_MODULE:= libandroidfw
 LOCAL_MODULE_TAGS := optional
 LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+ifeq ($(ZIP_OPTIMIZATION_NO_INTEGRITY),true)
+    LOCAL_CFLAGS += -DZIP_NO_INTEGRITY
+endif
 LOCAL_SRC_FILES:= $(hostSources)
 LOCAL_C_INCLUDES := external/zlib
 
@@ -73,7 +76,9 @@ LOCAL_SHARED_LIBRARIES := \
     libz
 
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
+ifeq ($(ZIP_OPTIMIZATION_NO_INTEGRITY),true)
+    LOCAL_CFLAGS += -DZIP_NO_INTEGRITY
+endif
 include $(BUILD_SHARED_LIBRARY)
 
 
index a6f6d8c..25d5c56 100644 (file)
@@ -148,6 +148,22 @@ bool ZipFileRO::startIteration(void** cookie, const char* prefix, const char* su
     return true;
 }
 
+#ifdef ZIP_NO_INTEGRITY
+ZipEntryRO ZipFileRO::nextEntryNoIntegrity(void* cookie)
+{
+    _ZipEntryRO* ze = reinterpret_cast<_ZipEntryRO*>(cookie);
+    int32_t error = NextNoIntegrity(ze->cookie, &(ze->entry), &(ze->name));
+    if (error) {
+        if (error != -1) {
+            ALOGW("Error iteration over %s: %s", mFileName, ErrorCodeString(error));
+        }
+        return NULL;
+    }
+
+    return &(ze->entry);
+}
+#endif
+
 ZipEntryRO ZipFileRO::nextEntry(void* cookie)
 {
     _ZipEntryRO* ze = reinterpret_cast<_ZipEntryRO*>(cookie);