From b442ab7daf1b77ca2b738ca414e817490f2cf718 Mon Sep 17 00:00:00 2001 From: xiajiang Date: Wed, 17 Feb 2016 13:59:14 -0500 Subject: [PATCH] Enable the PRC compatibility package feature for PRC market In PRC market, some APKs are packed in non-standard way, that is, the x86(_64) libraries aren't workable although they're found in the APK. This patch intends to relieve the impact from below 2 defects, which is based-on the heuristic algorithm. NOTE: To enable this feature, set "PRC_COMPATIBILITY_PACKAGE := true" in device BoardConfig.mk before enabling houdini. 1. Missing x86(_64) libraries: The x86(_64) libraries are ported and existing in the APK. But it's incomplete, and not workable. 2. Mixed arm(64) libraries: Several libraries are existing in lib/x86(_64)/ directory in the APK. But some of them are arm(64) libraries, instead of x86(_64) ones. All of above always cause APP crash if installed x86(_64) libraries by PackageManager. This patch aims to improve PackageManager to figure out these defects and install arm(64) libraries to run the APP with houdini support. The basic idea is to compare x86(_64) libraries with arm(64) alternatives to determine which one should be workable. To customize it for specific APPs, 3 lists are provided under /system/vendor/etc/misc/ on the device. 1. /system/vendor/etc/misc/.OEMWhiteList: This patch will be disabled for the APPs containing in the OEMWhiteList 2. /system/vendor/etc/misc/.OEMBlackList: The APP is enforced to install the arm(64) libraries if existed. 3. /system/vendor/etc/misc/.ThirdPartySO: This is another list which contains the names of all 3rd-party libraries, which will impact on the final decision of APP installation. Change-Id: I2613d9ebc8fe012c801f4a38fc5dede413f15a91 Tracked-On: https://jira01.devtools.intel.com/browse/OAM-20470 Signed-off-by: xiajiang Reviewed-on: https://android.intel.com:443/471490 --- .../internal/content/NativeLibraryHelper.java | 21 +- core/jni/Android.mk | 11 + core/jni/abipicker/ABIPicker.cpp | 701 +++++++++++++++++++++ core/jni/abipicker/ABIPicker.h | 55 ++ core/jni/abipicker/ELFLite.h | 58 ++ core/jni/abipicker/OEMBlackList | 1 + core/jni/abipicker/OEMWhiteList | 1 + core/jni/abipicker/ThirdPartySO | 309 +++++++++ ...ndroid_internal_content_NativeLibraryHelper.cpp | 62 ++ 9 files changed, 1213 insertions(+), 6 deletions(-) create mode 100644 core/jni/abipicker/ABIPicker.cpp create mode 100644 core/jni/abipicker/ABIPicker.h create mode 100644 core/jni/abipicker/ELFLite.h create mode 100644 core/jni/abipicker/OEMBlackList create mode 100644 core/jni/abipicker/OEMWhiteList create mode 100644 core/jni/abipicker/ThirdPartySO diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index f479f4feca35..851d97b9b034 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -76,6 +76,7 @@ public class NativeLibraryHelper { final long[] apkHandles; final boolean multiArch; final boolean extractNativeLibs; + final String pkgName; public static Handle create(File packageFile) throws IOException { try { @@ -89,15 +90,15 @@ public class NativeLibraryHelper { public static Handle create(Package pkg) throws IOException { return create(pkg.getAllCodePaths(), (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0, - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0); + (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0, pkg.packageName); } public static Handle create(PackageLite lite) throws IOException { - return create(lite.getAllCodePaths(), lite.multiArch, lite.extractNativeLibs); + return create(lite.getAllCodePaths(), lite.multiArch, lite.extractNativeLibs,lite.packageName); } private static Handle create(List codePaths, boolean multiArch, - boolean extractNativeLibs) throws IOException { + boolean extractNativeLibs,String pkgName) throws IOException { final int size = codePaths.size(); final long[] apkHandles = new long[size]; for (int i = 0; i < size; i++) { @@ -112,13 +113,14 @@ public class NativeLibraryHelper { } } - return new Handle(apkHandles, multiArch, extractNativeLibs); + return new Handle(apkHandles, multiArch, extractNativeLibs, pkgName); } - Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs) { + Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs, String pkgName) { this.apkHandles = apkHandles; this.multiArch = multiArch; this.extractNativeLibs = extractNativeLibs; + this.pkgName=pkgName; mGuard.open("close"); } @@ -191,7 +193,13 @@ public class NativeLibraryHelper { public static int findSupportedAbi(Handle handle, String[] supportedAbis) { int finalRes = NO_NATIVE_LIBRARIES; for (long apkHandle : handle.apkHandles) { - final int res = nativeFindSupportedAbi(apkHandle, supportedAbis); + int res; + if (true) { + res = nativeFindSupportedAbiReplace(apkHandle, supportedAbis, handle.pkgName); + } else { + res = nativeFindSupportedAbi(apkHandle, supportedAbis); + } + if (res == NO_NATIVE_LIBRARIES) { // No native code, keep looking through all APKs. } else if (res == INSTALL_FAILED_NO_MATCHING_ABIS) { @@ -215,6 +223,7 @@ public class NativeLibraryHelper { private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis); + private native static int nativeFindSupportedAbiReplace(long handle, String[] supportedAbis,String pkgName); // Convenience method to call removeNativeBinariesFromDirLI(File) public static void removeNativeBinariesLI(String nativeLibraryPath) { if (nativeLibraryPath == null) return; diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 6dabc77b0e58..e6858f322fc5 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -266,6 +266,17 @@ LOCAL_SHARED_LIBRARIES += \ libhwui \ libdl +ifeq ($(PRC_COMPATIBILITY_PACKAGE),true) + LOCAL_CFLAGS += -D_PRC_COMPATIBILITY_PACKAGE_ + LOCAL_C_INCLUDES += $(LOCAL_PATH)/abipicker + LOCAL_SRC_FILES += abipicker/ABIPicker.cpp + LOCAL_POST_INSTALL_CMD := $(hide) \ + mkdir -p $(TARGET_OUT_VENDOR)/etc/misc/; \ + cp -f $(LOCAL_PATH)/abipicker/OEMWhiteList $(TARGET_OUT_VENDOR)/etc/misc/.OEMWhiteList; \ + cp -f $(LOCAL_PATH)/abipicker/OEMBlackList $(TARGET_OUT_VENDOR)/etc/misc/.OEMBlackList; \ + cp -f $(LOCAL_PATH)/abipicker/ThirdPartySO $(TARGET_OUT_VENDOR)/etc/misc/.ThirdPartySO +endif + # we need to access the private Bionic header # in com_google_android_gles_jni_GLImpl.cpp LOCAL_C_INCLUDES += bionic/libc/private diff --git a/core/jni/abipicker/ABIPicker.cpp b/core/jni/abipicker/ABIPicker.cpp new file mode 100644 index 000000000000..8fffc7cc1376 --- /dev/null +++ b/core/jni/abipicker/ABIPicker.cpp @@ -0,0 +1,701 @@ +#define LOG_TAG "ABIPicker" + +#include "ABIPicker.h" +#include "ELFLite.h" + +#include +#include + +namespace android { +#define ARR_SIZE(x) (sizeof(x)/sizeof(x[0])) + +#define SO_NAME_MAX (4096) +#define IMPOSSIBLE_LIB_NAME "/mixed/" +#define IMPOSSIBLE_LIB_LEN (sizeof(IMPOSSIBLE_LIB_NAME)-1) +#define ARMABI "armeabi" +#define ARMV7ABI "armeabi-v7a" +#define ARM64ABI "arm64-v8a" +#define X86ABI "x86" +#define X8664ABI "x86_64" +#define ARMABI_NAME_PREFIX "arm" + +#define APK_LIB "lib/" +#define APK_LIB_LEN (sizeof(APK_LIB) - 1) +//#define PICK_LOGGER //flag to debug +#ifdef PICK_LOGGER +#define P_LOG(...) ALOGI(__VA_ARGS__) +#else +#define P_LOG(...) +#endif + +#define OEMWHITE "/system/vendor/etc/misc/.OEMWhiteList" +#define OEMBLACK "/system/vendor/etc/misc/.OEMBlackList" +#define THIRDPARTY "/system/vendor/etc/misc/.ThirdPartySO" + +// load once, hold until poweroff +static Vector thirdPartySO; +static Vector cfgWhite; +static Vector cfgBlack; +static bool thirdload = false; +static bool whiteload = false; +static bool blackload = false; + +static const char* iaRelated[] = {"intel", "atom", "x86", "x64"}; + +////////////////////////////////////////////////////////////////////// +void getConfig(const char* cfgFile , Vector& cfgVec) { + FILE* fp = fopen(cfgFile, "r"); + int read = -1; + char *line = NULL; + size_t len = 0; + + while ((read = getline(&line, &len, fp)) != -1) { + int i = 0 , j = 0; + char *cfgline = (char*)malloc(len); + if (!cfgline) { + P_LOG("malloc error"); + break; + } + for (i = 0; i < read; i++) { + if (!isspace(line[i])) { + cfgline[j++] = line[i]; + } + } + cfgline[j] = '\0'; + cfgVec.push_back(cfgline); + P_LOG("orignal %s , vec: %s ", line, cfgline); + } + if (line != NULL) + free(line); + fclose(fp); +} + +////////////////////////////////////////////////////////////////////// +void freeAllString(Vector& list) { + Vector::iterator it = list.begin(); + while (it != list.end()) { + if (*it != NULL) { + P_LOG("freeAllSring %p , %s", it, *it); + free(*it); + *it = NULL; + } + it++; + } +} + +////////////////////////////////////////////////////////////////////// +bool isInOEMWhiteList(const char* pkgName) { + bool result = false; + if (!pkgName) return result; + + if (!whiteload) { + getConfig(OEMWHITE, cfgWhite); + whiteload = true; + } + + Vector::iterator it = cfgWhite.begin(); + for (; it != cfgWhite.end(); it++) { + P_LOG("whitelist : %s", *it); + if (0 == strcmp(pkgName, *it)) { + ALOGI("found %s in whitelist", pkgName); + result = true; + break; + } + } + return result; +} + +////////////////////////////////////////////////////////////////////// +bool isInOEMBlackList(const char* pkgName) { + bool result = false; + if (!pkgName) return result; + + if (!blackload) { + getConfig(OEMBLACK, cfgBlack); + blackload = true; + } + + Vector::iterator it = cfgBlack.begin(); + for (; it != cfgBlack.end(); it++) { + if (0 == strcmp(pkgName, *it)) { + ALOGI("found %s in blacklist", pkgName); + result = true; + break; + } + } + return result; +} + + +////////////////////////////////////////////////////////////////////// +bool isReliableLib(Vector& libList) { + unsigned sz = libList.size(); + int len = ARR_SIZE(iaRelated); + for (unsigned i = 0; i < sz; i++) { + for (int j=0; j < len; j++) { + if (NULL != strstr(libList[i], iaRelated[j])) { + return true; + } + } + } + + return false; +} + + +////////////////////////////////////////////////////////////////////// +static bool isValidELF(char* buffer) { + if (buffer[EI_MAG0] != ELFMAG0 && + buffer[EI_MAG1] != ELFMAG1 && + buffer[EI_MAG2] != ELFMAG2 && + buffer[EI_MAG3] != ELFMAG3) { + return false; + } + return true; +} + +// assume that x86 has the only machine-code 3, and x86_64 62 +static bool isMixedLib(char* libCur, char* buffer) { + bool isX86_64 = (0 == strcmp(libCur, X8664ABI)) ? true: false; + uint16_t machine_code = *((uint16_t*)(&buffer[ELF_MACHINE_OFFSET])); + bool mixed = false; + if (isX86_64) { + if (machine_code != EM_X86_64) + mixed = true; + } else { + if (machine_code != EM_386) + mixed = true; + } + return mixed; +} + +static bool isInThirdPartySOList(char* libName) { + if (!libName) return false; + size_t libLen = strlen(libName); + bool ret = false; + size_t sz = thirdPartySO.size(); + for (size_t i = 0; i < sz; i++) { + size_t n = strlen(thirdPartySO[i]); + // three for prefix "lib", and 3 for suffix ".so" + if ((libLen == (n+6))&&(0 == strncmp(libName + 3, thirdPartySO[i], n))) { + ret = true; + break; + } + } + P_LOG("ABIpicker libName %s,In Third %d", libName, ret); + return ret; +} + +static void insertionSort(Vector& list) { + P_LOG("in insertionSort, list size = %d\n", list.size()); + + for (size_t i = 1; i < list.size(); i++) { + char* x = list[i]; + + int j = i - 1; + P_LOG("sort 1. x=%s, i=%d, j=%d\n", x, i, j); + while (j >= 0 && (strcmp(list[j], x) > 0)) { + list.replaceAt(list[j], j + 1); + j--; + } + list.replaceAt(x, j + 1); + } +} + + + +////////////////////////////////////////////////////////////////////// +// Use armRef as a reference, compare all libraries of iaRef with all +// libraries of armRef. If both are match, iaRef will be returned with +// *result and true is return value. Or else, *result is rawResult and +// false is return value +bool ABIPicker::compare(char* armRef, char* iaRef, + char* rawResult, char** result) { + bool ret = true; + *result = rawResult; + + do { + assert(armRef != NULL); + if (0 == strlen(armRef)) { + *result = strlen(iaRef) > 0 ? iaRef : rawResult; + ret = strlen(iaRef) > 0 ? true : false; + break; + } + assert(iaRef != NULL); + if (0 == strlen(iaRef)) { + *result = armRef; + ret = false; + break; + } + + Vector* iaRefList = getLibList(iaRef); + Vector* armRefList = getLibList(armRef); + + // if contains the key words in iaRelated, just return true + if (isReliableLib(*iaRefList)) { + *result = iaRef; + break; + } + + if (compareLibList(*iaRefList, *armRefList)) { + *result = iaRef; + break; + } + + size_t iaIsvLibCount = 0; + size_t armIsvLibCount = 0; + if (!compare3rdPartyLibList(iaRef, armRef, + &iaIsvLibCount, &armIsvLibCount)) { + *result = armRef; + ret = false; + break; + } + + if (iaIsvLibCount > 0) { + *result = iaRef; + break; + } + + *result = armRef; + ret = false; + } while (false); + + ALOGV("%s Vs. %s, return %s\n", + iaRef ? iaRef : "NULL", + armRef ? armRef : "NULL", *result); + return ret; +} + +bool ABIPicker::compareLibList(Vector& iaRefList, + Vector& armRefList) { + if (iaRefList.size() != armRefList.size()) { + return false; + } + + Vector::iterator itIa = iaRefList.begin(); + Vector::iterator itArm = armRefList.begin(); + while (itIa != iaRefList.end() && itArm != armRefList.end()) { + char* iaLibName = *itIa; + char* armLibName = *itArm; + + // NOTE: + // WIN treats file names in-case-sensitive, + // but LINUX treats them case-sensitive. + if (0 != strcmp(iaLibName, armLibName)) { + return false; + } + + itIa++; + itArm++; + } + + return true; +} + +bool ABIPicker::compare3rdPartyLibList( + char* iaRef, char* armRef, + size_t* iaIsvLibCount, size_t* armIsvLibCount) { + Vector* iaRefList = getLibList(iaRef); + Vector* armRefList = getLibList(armRef); + + Vector* armRef3rdPartyLibList = new Vector(); + Vector::iterator itArm = armRefList->begin(); + + // Load thirdPartyso + if (!thirdload) { + getConfig(THIRDPARTY, thirdPartySO); + thirdload = true; + } + while (itArm != armRefList->end()) { + char* armLibName = *itArm; + if (isInThirdPartySOList(armLibName)) { + armRef3rdPartyLibList->push_back(armLibName); + } else { + (*armIsvLibCount)++; + } + + itArm++; + } + + Vector::iterator itIa = iaRefList->begin(); + Vector* iaRef3rdPartyLibList = new Vector(); + while (itIa != iaRefList->end()) { + char* iaLibName = *itIa; + if (isInThirdPartySOList(iaLibName)) { + iaRef3rdPartyLibList->push_back(iaLibName); + } else { + (*iaIsvLibCount)++; + } + + itIa++; + } + return compareLibList(*iaRef3rdPartyLibList, *armRef3rdPartyLibList); +} + +char* ABIPicker::getAbiName(int abi) { + if (abi < 0 || (unsigned)abi >= mLibList->size()) { + return NULL; + } + + char* ret = NULL; + int index = 0; + Vector::iterator it = mLibList->begin(); + while (it != mLibList->end()) { + if (index == abi) { + ret = (*it)->abiName; + break; + } + + index++; + it++; + } + + return ret; +} + +int ABIPicker::getAbiIndex(const char* abiName) { + int ret = -1; + + int index = 0; + Vector::iterator it = mLibList->begin(); + while (it != mLibList->end()) { + if (0 == strcmp(abiName, (*it)->abiName)) { + ret = index; + break; + } + + index++; + it++; + } + + return ret; +} + +Vector* ABIPicker::getLibList(const char* abiName) { + Vector* ret = NULL; + Vector::iterator it = mLibList->begin(); + while (it != mLibList->end()) { + if (0 == strcmp(abiName, (*it)->abiName)) { + ret = (*it)->libNameList; + break; + } + it++; + } + P_LOG("getLibList of %s return %p\n", abiName, ret); + return ret; +} + + +size_t ABIPicker::getSpecficABILibCount(const char* abiName) { + Vector* specificAbiLibList = getLibList(abiName); + return specificAbiLibList && specificAbiLibList->size(); +} + +bool ABIPicker::foundMixedELF(const char* abiName) { + Vector* libNameList = getLibList(abiName); + if (!libNameList) { + return false; + } + if (libNameList->size() == 0) { + return false; + } + + if (0 != strcasecmp(*(libNameList->begin()), IMPOSSIBLE_LIB_NAME)) { + return false; + } + + return true; +} + + +////////////////////////////////////////////////////////////////////// +ABIPicker::ABIPicker(const char* pkgName, Vector abiList) { + mLibList = new Vector(); + mpkgName = (char*)malloc(strlen(pkgName)+1); + if (!mpkgName) { + P_LOG("ABIPicker Construct Allocated space fails"); + } else { + strcpy(mpkgName, pkgName); + } + Vector::iterator it = abiList.begin(); + while (it != abiList.end()) { + if (!(*it)) { + break; + } + + struct libInfo* tmp = (struct libInfo*)calloc(1, + sizeof(struct libInfo)); + if (!tmp) { + P_LOG("ABIPicker Construct Allocated space fail %s", (*it)->c_str()); + break; + } + + snprintf(tmp->abiName, (*it)->size() + 1, "%s", (*it)->c_str()); + tmp->libNameList = new Vector(); + P_LOG("ABIPicker Construct %s , libNameList: %p", + tmp->abiName, tmp->libNameList); + mLibList->push_back(tmp); + it++; + } +} + +ABIPicker::~ABIPicker(void) { + if(NULL != mpkgName) { + free(mpkgName); + mpkgName = NULL; + } + Vector::iterator it = mLibList->begin(); + while (it != mLibList->end()) { + freeAllString(*((*it)->libNameList)); + (*it)->libNameList->clear(); + delete (*it)->libNameList; + (*it)->libNameList = NULL; + + free(*it); + *it = NULL; + it++; + } + mLibList->clear(); +} + +bool ABIPicker::buildNativeLibList(void* apkHandle) { + bool ret = false; + + if (!apkHandle) { + ALOGE("apkHandle is NULL\n"); + return ret; + } + + ZipFileRO* zipFile = reinterpret_cast(apkHandle); + void* cookie = NULL; + if (!zipFile->startIteration(&cookie)) { + ALOGE("apk file is broken\n"); + return ret; + } + + ZipEntryRO next = NULL; + char* unCompBuff = NULL; + char fileName[SO_NAME_MAX + 1]; + while ((next = zipFile->nextEntry(cookie))) { + if (zipFile->getEntryFileName(next, fileName, SO_NAME_MAX)) { + ALOGE("apk file is broken, can not get entry name\n"); + ret = false; + break; + } + fileName[SO_NAME_MAX] = '\0'; + + // Make sure we're in the lib directory of the ZIP. + // find out entries with such names: "lib/xxxxxxx" or "lib/" + if (strncmp(fileName, APK_LIB, APK_LIB_LEN)) { + continue; + } + + // find out any invalid ELF file + uint32_t unCompLen = 0; + if (!zipFile->getEntryInfo(next, NULL, &unCompLen, NULL, NULL, NULL, + NULL)) { + ALOGE("apk file is broken, can not get entry info\n"); + ret = false; + break; + } + + if (unCompLen == 0) { + ALOGV("skip a empty file(%s)\n", fileName); + continue; + } + + if (!unCompBuff) { + free(unCompBuff); + unCompBuff = NULL; + } + + unCompBuff = (char*)malloc(unCompLen); + if (!unCompBuff) { + ALOGE("malloc failed size %d\n", unCompLen); + ret = false; + break; + } + + // THE MOST TIME COST OPERATION + if (!zipFile->uncompressEntry(next, unCompBuff, unCompLen)) { + ALOGE("%s: uncompress failed\n", fileName); + ret = false; + break; + } + + if (!isValidELF(unCompBuff)) { + ALOGI("skip a fake .ELF file(%s)\n", fileName); + continue; + } + + // It is a real .so file, prepare to record + // find abi name and focus on what we care: arm(s) and x86(s) + // at least lastSlash points to the end of "lib/" + const char* lastSlash = strrchr(fileName, '/'); + const char* cpuAbiOffset = fileName + APK_LIB_LEN; + // just in case if fileName is in an abnormal format, like lib/libname, + // lib//libname + if (lastSlash <= cpuAbiOffset) { + ALOGI("skip a invalid lib file(%s)\n", fileName); + continue; + } + + const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset; + char curAbiName[ABI_NAME_MAX_LENGTH]; + if (cpuAbiRegionSize >= ABI_NAME_MAX_LENGTH) { + continue; + } + snprintf(curAbiName, cpuAbiRegionSize + 1, "%s", cpuAbiOffset); + + Vector* libListOfCurAbi = getLibList(curAbiName); + if (!libListOfCurAbi) { + P_LOG("getLibList of %s return NULL\n", curAbiName); + continue; + } + + // mixed arm elf in lib/x86 or lib/x86_64 + // but we don't consider a compareable scenario in lib/arm* + if (0 == strcmp(curAbiName, X86ABI) || + 0 == strcmp(curAbiName, X8664ABI)) { + if (!libListOfCurAbi->empty()) { + char* firstElement = libListOfCurAbi->itemAt(0); + if (0 == strcmp(firstElement, IMPOSSIBLE_LIB_NAME)) { + // won't add any new into the list if found mixed + // lib before + P_LOG("won't count count if found mixed lib before"); + continue; + } + } + + if (isMixedLib(curAbiName, unCompBuff)) { + P_LOG("found mixed lib(%s) in lib/%s/", curAbiName, fileName); + freeAllString(*libListOfCurAbi); + libListOfCurAbi->clear(); + char* mixedLib = (char*)malloc(IMPOSSIBLE_LIB_LEN+1); + if (!mixedLib) { + ALOGE("malloc failed size %d", IMPOSSIBLE_LIB_LEN + 1); + ret = false; + break; + } + strcpy(mixedLib, (char*)IMPOSSIBLE_LIB_NAME); + mixedLib[IMPOSSIBLE_LIB_LEN] ='\0'; + libListOfCurAbi->push_back(mixedLib); + continue; + } + } + + // now, lastSlash should point to lib name + lastSlash++; + const size_t libNameSize = strlen(lastSlash); + char* curLibName = (char*)malloc(libNameSize+1); + if (!curLibName) { + ALOGE("malloc failed size %d\n", libNameSize+1); + ret = false; + break; + } + strcpy(curLibName, lastSlash); + curLibName[libNameSize] = '\0'; + + libListOfCurAbi->push_back(curLibName); + + ret = true; + } + + if (unCompBuff) { + free(unCompBuff); + unCompBuff = NULL; + } + + zipFile->endIteration(cookie); + + for (unsigned i = 0; i < mLibList->size(); i++) { + struct libInfo* tmp = mLibList->itemAt(i); + insertionSort(*(tmp->libNameList)); + } + return ret; +} + +int ABIPicker::pickupRightABI(int sysPrefer) { + char* sysPreferAbiName = getAbiName(sysPrefer); + if (!sysPreferAbiName) { + return sysPrefer; + } + + bool is64BitPrefer = (0 == strcmp(sysPreferAbiName, X8664ABI)); + bool x8664HasMixedELF = foundMixedELF(X8664ABI); + bool x86HasMixedELF = foundMixedELF(X86ABI); + + size_t armv7LibCount = getSpecficABILibCount(ARMV7ABI); + size_t armv5LibCount = getSpecficABILibCount(ARMABI); + size_t armv8LibCount = getSpecficABILibCount(ARM64ABI); + size_t x86LibCount = x86HasMixedELF ? 0 : getSpecficABILibCount(X86ABI); + size_t x8664LibCount = x8664HasMixedELF ? 0 : getSpecficABILibCount(X8664ABI); + P_LOG("armv7LibCount:%d armv5LibCount:%d armv8LibCount:%d x86LibCount:%d x8664LibCount:%d", armv7LibCount, armv5LibCount, armv8LibCount, x86LibCount, x8664LibCount); + + // in OEMBlackList, need to be supported by bt + // but in case of armlib doesn't exist, we choose x86 or x86_64 + if (isInOEMBlackList(mpkgName)) { + if (armv7LibCount > 0) { + return getAbiIndex(ARMV7ABI); + } else if (armv5LibCount > 0) { + return getAbiIndex(ARMABI); + } else if (armv8LibCount > 0) { + return getAbiIndex(ARM64ABI); + } + } + + char arm64Ref[ABI_NAME_MAX_LENGTH]; + if (armv8LibCount > 0) { + snprintf(arm64Ref, sizeof(ARM64ABI), "%s", ARM64ABI); + } else { + arm64Ref[0] = '\0'; + } + + char arm32Ref[ABI_NAME_MAX_LENGTH]; + if (armv7LibCount > 0) { + snprintf(arm32Ref, sizeof(ARMV7ABI), "%s", ARMV7ABI); + } else if (armv5LibCount > 0) { + snprintf(arm32Ref, sizeof(ARMABI), "%s", ARMABI); + } else { + arm32Ref[0] = '\0'; + } + + char ia32Ref[ABI_NAME_MAX_LENGTH]; + if (x86LibCount > 0) { + snprintf(ia32Ref, sizeof(X86ABI), "%s", X86ABI); + } else { + ia32Ref[0] = '\0'; + } + + char ia64Ref[ABI_NAME_MAX_LENGTH]; + if (x8664LibCount > 0) { + snprintf(ia64Ref, ABI_NAME_MAX_LENGTH, "%s", X8664ABI); + } else { + ia64Ref[0] = '\0'; + } + + char* retAbiName = sysPreferAbiName; + do { + // # The basic rule is: + // - on 32 bit system, compare ia32Ref native libraries with + // arm32Ref native libraries. If pass, return ia32Ref . + // If fail, return arm32Ref. + // - on 64 bit system, IA has two chances. if ia64Ref native + // libraries can't pass the comparation with arm64Ref, we should + // run the comparation again with ia32Ref + if (is64BitPrefer) { + if (!compare(arm64Ref, ia64Ref, sysPreferAbiName, &retAbiName)) { + char rawRes[ABI_NAME_MAX_LENGTH]; + strcpy(rawRes, retAbiName); + compare(arm32Ref, ia32Ref, rawRes, &retAbiName); + } + } else { + compare(arm32Ref, ia32Ref, sysPreferAbiName, &retAbiName); + } + } while (false); + int ret = getAbiIndex(retAbiName); + ALOGI("selected abi %s(%d) for %s", retAbiName, ret, mpkgName); + return ret; +} + +} // namespace android diff --git a/core/jni/abipicker/ABIPicker.h b/core/jni/abipicker/ABIPicker.h new file mode 100644 index 000000000000..36453644b6af --- /dev/null +++ b/core/jni/abipicker/ABIPicker.h @@ -0,0 +1,55 @@ +#ifndef _ABIPICKER_H_ +#define _ABIPICKER_H_ + +#include +#include +#include +#include + +#include +#include +namespace android { +// assumption: the length of name of any abi type in abi list, +// like armeabi-v7a, armeabi, x86, is not longer than 64 +#define ABI_NAME_MAX_LENGTH (64) +/* +class LibInfo { + public: + LibInfo(char* s, List list); + ~LibInfo(void); + + private: + char abiName[ABI_NAME_MAX_LENGTH]; + List libNameList; +}; +*/ + +class ABIPicker { + public: + explicit ABIPicker(const char* pkgName,Vector abiList); + ~ABIPicker(void); + + bool buildNativeLibList(void* apkHandle); + int pickupRightABI(int sysPrefer); + private: + struct libInfo{ + char abiName[ABI_NAME_MAX_LENGTH]; + Vector* libNameList; + }; + Vector* mLibList; + char* mpkgName; + + bool foundMixedELF(const char* abiName); + bool compare(char* armRef, char* iaRef, char* rawResult, char** result); + bool compareLibList(Vector& iaRefList, Vector& armRefList); + bool compare3rdPartyLibList( char* iaRef, char* armRef, + size_t* iaIsvLibCount, size_t* armIsvLibCount); + char* getAbiName(int abi); + int getAbiIndex(const char* abiName); + size_t getSpecficABILibCount(const char* abiName); + Vector* getLibList(const char* abiName); +}; + +bool isInOEMWhiteList(const char* pkgName); +} // namespace android +#endif // _ABIPICKER_H_ diff --git a/core/jni/abipicker/ELFLite.h b/core/jni/abipicker/ELFLite.h new file mode 100644 index 000000000000..e609e8ac4595 --- /dev/null +++ b/core/jni/abipicker/ELFLite.h @@ -0,0 +1,58 @@ +#ifndef _ELFLITE_H__ +#define _ELFLITE_H__ + +#include +#include +#include +#include +#include + +namespace android { +#define EI_NIDENT 16 /* Size of e_ident[] */ + +/* + * Fields in e_ident[] + */ +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7F /* Magic number byte 0 */ +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* + * according to implementations of ELF Header + * unsigned char e_ident[16]; // ELF "magic number" + * unsigned char e_type[2]; // Identifies object file type + * unsigned char e_machine[2]; // Specifies required architecture + */ +#define ELF_MACHINE_OFFSET 18 + +/* + * Values for e_machine, which identifies the architecture. These numbers + * are officially assigned by registry@sco.com. See below for a list of + * ad-hoc numbers used during initial development. + * Please always sync them. + */ +#define EM_386 3 /* Intel 80386 */ +#define EM_486 6 /* Intel 80486 */ +#define EM_860 7 /* Intel 80860 */ +#define EM_960 19 /* Intel 80960 */ +#define EM_ARM 40 /* ARM */ +#define EM_IA_64 50 /* Intel IA-64 Processor */ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_8051 165 /* Intel 8051 and variants */ +#define EM_L1OM 180 /* Intel L1OM */ +#define EM_K1OM 181 /* Intel K1OM */ +#define EM_INTEL182 182 /* Reserved by Intel */ +#define EM_AARCH64 183 /* ARM 64-bit architecture */ +#define EM_ARM184 184 /* Reserved by ARM */ +#define EM_INTEL205 205 /* Reserved by Intel */ +#define EM_INTEL206 206 /* Reserved by Intel */ +#define EM_INTEL207 207 /* Reserved by Intel */ +#define EM_INTEL208 208 /* Reserved by Intel */ +#define EM_INTEL209 209 /* Reserved by Intel */ +} // namespace android +#endif // _ELFLITE_H__ diff --git a/core/jni/abipicker/OEMBlackList b/core/jni/abipicker/OEMBlackList new file mode 100644 index 000000000000..5dfbf4eead20 --- /dev/null +++ b/core/jni/abipicker/OEMBlackList @@ -0,0 +1 @@ +com.ilongyuan.implosion* diff --git a/core/jni/abipicker/OEMWhiteList b/core/jni/abipicker/OEMWhiteList new file mode 100644 index 000000000000..d7f48988e3a2 --- /dev/null +++ b/core/jni/abipicker/OEMWhiteList @@ -0,0 +1 @@ +com.alensw.PicFolder diff --git a/core/jni/abipicker/ThirdPartySO b/core/jni/abipicker/ThirdPartySO new file mode 100644 index 000000000000..81cf0703124a --- /dev/null +++ b/core/jni/abipicker/ThirdPartySO @@ -0,0 +1,309 @@ +aacdecoder +aac-encoder +aal +aal_honeycomb +aal_jellybean +ads +aisound +aitalk +almixer +amapv3 +amapv301 +amapv301ex +amrcodec +amrnb +analytics +andengine +andenginephysicsbox2dextension +androidgl20 +app_baidumapapplib_v2_0_0 +app_baidumapapplib_v2_1_0 +app_baidumapapplib_v2_1_1 +app_baidumapapplib_v2_1_2 +app_baidunaviapplib +application +arm +armplugin +avcodec +avdevice +avfilter +avformat +aviary_exif +aviary_moalite +aviary_native +avutil +baidumapsdk_v2_1_3 +baidumapsdk_v2_2_0 +baidumapsdk_v2_3_0 +baidumapsdk_v2_3_1 +baidumapsdk_v2_3_5 +baidumapvos_v2_1_3 +bdmoplusmd5_v1 +bdpush_v1_0 +bdvoicerecognitionclient_v1 +bdvoicesearchclient_v2 +bmapapiengine +bmapapiengine_v1_3_0 +bmapapiengine_v1_3_1 +bmapapiengine_v1_3_2 +bmapapiengine_v1_3_3 +bmapapiengine_v1_3_4 +bmapapiengine_v1_3_5 +box2d +bspatch +bspatch +bullet +cardiodecider +cardiorecognizer +cardiorecognizer_tegra2 +casdkjni +cat +cftutils +chaosvmp +chatscript001 +chipmunk +cnpackage +cocos2d +cocos2dcpp +cocosdenshion +cocosdenshion +core +corona +coronaprovider.gamenetwork.corona +cpudetect +crittercism-ndk +crypto +cryptox +curl +cyberplayer +cyberplayer-core +database_sqlcipher +dejavu-1.0.1 +des +dexhelper +dexhelper-x86 +dianjin-jni +dodo +dropboxsync +ejtts +emu +emumedia +encode +entryex +exec +execmain +exif_extended +faceppapi +fastpay +fb_jpegturbo +ffmpeg +ffmpeg001 +fmodevent +fmodex +freetype +game +game_logic +gamenetwork +gba +gbd +gdx +gdx-freetype +gif +gnustl_shared +gpuimage-library +gwallet +hci_asr +hci_asr_jni +hci_sys +hci_sys_jni +hci_tts +hci_tts_jni +hci_tts_local_n6_synth +hellolua +iap +iconv +identifyapp +immemulatorj +increment +iomx-gingerbread +iomx-hc +iomx-ics +jni +jni_latinime +jniavcodec +jniavdevice +jniavfilter +jniavformat +jniavutil +jnicvkernels +jnigraphics +jniopencv_core +jniopencv_imgproc +jnipostproc +jniswresample +jniswscale +jnlua5.1 +jpush +json +jtopus +jtspeex +jtz +kinfoc +lame +lbs +lept +letter_xiaokun.n6.voclib +licensing +litedes +locsdk_2.2 +locsdk_2.3 +locsdk_2.4 +locsdk_2_4 +locsdk3 +locsdk4 +locsdk4b +lptcpjin +lthj_unipaybusiness20121012 +lthj_unipaybusiness20121217 +lthj_unipaybusiness20130328 +lua +luajava +mad +main +mame4all +mame4all-jni +mapv3ex +md5 +megjb +minimapv320 +mmdb +mmsdkjni +mobage +mono +monodroid +moplusmd5 +mp3lame +mpg123 +msc +msfboot +native +nativerqd +nes +nexadaptation_layer_for_dlsdk +nexalfactory +nexcal_aac_armv5 +nexcal_aac_armv6 +nexcal_aac_armv7 +nexcal_closedcaption +nexcal_h264_armv5 +nexcal_h264_armv6 +nexcal_h264_armv7 +nexcal_mp3_armv6 +nexcal_qcom_iomx +nexcal_ttml +nexcralbody_mc_jb +nexplayerengine +nexral_nw_jb +nexral_surf_gb +nexralbody_audio +nexralbody_audio_jb +nexralbody_video_cu +nexralbody_video_fr +nexralbody_video_fr3 +nexralbody_video_hc +nexralbody_video_is +nexralbody_video_jb +nexralbody_video_opengl +nmsp_speex +objc +ocrengine +ogg +openal +opencv_core +opencv_imgproc +opensles +paypalm_app_plugin_jar_360game +pinguoimagesdk +pjsipjni +plugins +protectclass +protobuf +push-socket +qrcodedecoder +qvodbase +qvodnetjni +redlaser +rsjni +rssupport +rtmp +s3eandroidmarketbilling_ext +sapi_so_1 +sdl +sdl_image +sdl_main +sdl_mixer +secexe +secexe.x86 +secmain +secmain.x86 +security +smsiap +smsprotocol +soundtouch +soundtouch +soundtouch001 +speex +sqlcipher_android +sqlite3 +ssl +stagefright_froyo +stagefright_honeycomb +stlport_shared +swresample +swscale +sync +sys +sys1.3.3 +tbb +tbt +tenpay_utils +tersafe +tess +tests +top-sdk +uffmpeg +unionpay +unity +usedes +ustoolkit +util +utility +vadlib +vi_voslib +vinit +voandroidvr_s20 +voandroidvr_s22 +voandroidvr_s23 +voh264dec +voh264dec_v7 +vorbis +vorbisidec +voswrapper +vpx +webp +wiengine +wiengine_binding +winetwork +wiskia +wisound +xiaokun.n6.voclib +xml2 +xmp +yeepaysdk +ysshared +yyutil +yzs_usc +zbarjni +zip +zxing-new +zxing-new-v7a diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index 364ac44ee0f6..4b88d198d03a 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -37,6 +37,10 @@ #include #include +#ifdef _PRC_COMPATIBILITY_PACKAGE_ +#include "ABIPicker.h" +#endif + #define APK_LIB "lib/" #define APK_LIB_LEN (sizeof(APK_LIB) - 1) @@ -55,6 +59,11 @@ #define TMP_FILE_PATTERN "/tmp.XXXXXX" #define TMP_FILE_PATTERN_LEN (sizeof(TMP_FILE_PATTERN) - 1) +#ifdef _PRC_COMPATIBILITY_PACKAGE_ +#define X86ABI "x86" +#define X8664ABI "x86_64" +#endif + namespace android { // These match PackageManager.java install codes @@ -513,6 +522,56 @@ com_android_internal_content_NativeLibraryHelper_findSupportedAbi(JNIEnv *env, j return (jint) findSupportedAbi(env, apkHandle, javaCpuAbisToSearch); } +static jint +com_android_internal_content_NativeLibraryHelper_findSupportedAbi_replace( + JNIEnv *env, + jclass clazz, + jlong apkHandle, + jobjectArray javaCpuAbisToSearch, + jstring apkPkgName) +{ +#ifdef _PRC_COMPATIBILITY_PACKAGE_ + const int numAbis = env->GetArrayLength(javaCpuAbisToSearch); + Vector supportedAbis; + for (int i = 0; i < numAbis; i++) { + ScopedUtfChars* abiName = new ScopedUtfChars(env, + (jstring)env->GetObjectArrayElement( + javaCpuAbisToSearch, i)); + supportedAbis.push_back(abiName); + } + + int abiType = findSupportedAbi(env, apkHandle, javaCpuAbisToSearch); + do { + + if (abiType < 0 || abiType >= numAbis ) break ; + // if one package's name is on OEM's specific white list, then the + // package should be installed as default + ScopedUtfChars name(env, apkPkgName); + if (isInOEMWhiteList(name.c_str())) { + break; + } + + if (0 != strcmp(supportedAbis[abiType]->c_str(), X86ABI) && + 0 != strcmp(supportedAbis[abiType]->c_str(), X8664ABI)){ + break; + } + ABIPicker picker(name.c_str(),supportedAbis); + if (!picker.buildNativeLibList((void*)apkHandle)) { + break; + } + + abiType = picker.pickupRightABI(abiType); + } while (false); + + for (int i = 0; i < numAbis; ++i) { + delete supportedAbis[i]; + } + return (jint)abiType; +#else + return (jint)findSupportedAbi(env, apkHandle, javaCpuAbisToSearch); +#endif +} + enum bitcode_scan_result_t { APK_SCAN_ERROR = -1, NO_BITCODE_PRESENT = 0, @@ -579,6 +638,9 @@ static const JNINativeMethod gMethods[] = { (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi}, {"hasRenderscriptBitcode", "(J)I", (void *)com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode}, + {"nativeFindSupportedAbiReplace", + "(J[Ljava/lang/String;Ljava/lang/String;)I", + (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi_replace}, }; -- 2.11.0