1 #define LOG_TAG "ABIPicker"
6 #include <androidfw/ZipFileRO.h>
7 #include <androidfw/ZipUtils.h>
10 #define ARR_SIZE(x) (sizeof(x)/sizeof(x[0]))
12 #define SO_NAME_MAX (4096)
13 #define IMPOSSIBLE_LIB_NAME "/mixed/"
14 #define IMPOSSIBLE_LIB_LEN (sizeof(IMPOSSIBLE_LIB_NAME)-1)
15 #define ARMABI "armeabi"
16 #define ARMV7ABI "armeabi-v7a"
17 #define ARM64ABI "arm64-v8a"
19 #define X8664ABI "x86_64"
20 #define ARMABI_NAME_PREFIX "arm"
22 #define APK_LIB "lib/"
23 #define APK_LIB_LEN (sizeof(APK_LIB) - 1)
24 //#define PICK_LOGGER //flag to debug
26 #define P_LOG(...) ALOGI(__VA_ARGS__)
31 #define OEMWHITE "/system/vendor/etc/misc/.OEMWhiteList"
32 #define OEMBLACK "/system/vendor/etc/misc/.OEMBlackList"
33 #define THIRDPARTY "/system/vendor/etc/misc/.ThirdPartySO"
35 // load once, hold until poweroff
36 static Vector <char*> thirdPartySO;
37 static Vector <char*> cfgWhite;
38 static Vector <char*> cfgBlack;
39 static bool thirdload = false;
40 static bool whiteload = false;
41 static bool blackload = false;
43 static const char* iaRelated[] = {"intel", "intl", "atom", "x86", "x64"};
45 //////////////////////////////////////////////////////////////////////
46 void getConfig(const char* cfgFile , Vector<char*>& cfgVec) {
47 FILE* fp = fopen(cfgFile, "r");
53 while ((read = getline(&line, &len, fp)) != -1) {
55 char *cfgline = (char*)malloc(len);
57 P_LOG("malloc error");
60 for (i = 0; i < read; i++) {
61 if (!isspace(line[i])) {
62 cfgline[j++] = line[i];
66 cfgVec.push_back(cfgline);
67 P_LOG("orignal %s , vec: %s ", line, cfgline);
74 //////////////////////////////////////////////////////////////////////
75 void freeAllString(Vector<char*>& list) {
76 Vector<char*>::iterator it = list.begin();
77 while (it != list.end()) {
79 P_LOG("freeAllSring %p , %s", it, *it);
87 //////////////////////////////////////////////////////////////////////
88 bool isInOEMWhiteList(const char* pkgName) {
90 if (!pkgName) return result;
93 getConfig(OEMWHITE, cfgWhite);
97 Vector<char*>::iterator it = cfgWhite.begin();
98 for (; it != cfgWhite.end(); it++) {
99 P_LOG("whitelist : %s", *it);
100 if (0 == strcmp(pkgName, *it)) {
101 ALOGI("found %s in whitelist", pkgName);
109 //////////////////////////////////////////////////////////////////////
110 bool isInOEMBlackList(const char* pkgName) {
112 if (!pkgName) return result;
115 getConfig(OEMBLACK, cfgBlack);
119 Vector<char*>::iterator it = cfgBlack.begin();
120 for (; it != cfgBlack.end(); it++) {
121 if (0 == strcmp(pkgName, *it)) {
122 ALOGI("found %s in blacklist", pkgName);
131 //////////////////////////////////////////////////////////////////////
132 bool isReliableLib(Vector<char*>& libList) {
133 unsigned sz = libList.size();
134 int len = ARR_SIZE(iaRelated);
135 for (unsigned i = 0; i < sz; i++) {
136 for (int j=0; j < len; j++) {
138 if (NULL != (p = strcasestr(libList[i], iaRelated[j]))) {
139 int lenIA = strlen(iaRelated[j]);
140 if (!isalpha(*(p+lenIA))) {
141 if (!isalpha(*(p-1)) || (p == (libList[i] + 3))) {
153 //////////////////////////////////////////////////////////////////////
154 static bool isValidELF(char* buffer) {
155 if (buffer[EI_MAG0] != ELFMAG0 &&
156 buffer[EI_MAG1] != ELFMAG1 &&
157 buffer[EI_MAG2] != ELFMAG2 &&
158 buffer[EI_MAG3] != ELFMAG3) {
164 // assume that x86 has the only machine-code 3, and x86_64 62
165 static bool isMixedLib(char* libCur, char* buffer) {
166 bool isX86_64 = (0 == strcmp(libCur, X8664ABI)) ? true: false;
167 uint16_t machine_code = *((uint16_t*)(&buffer[ELF_MACHINE_OFFSET]));
170 if (machine_code != EM_X86_64)
173 if (machine_code != EM_386)
179 // compare the given string with the length, igonre upper and lower
180 // len must be less than the length of two string
181 static bool ignoreCmp(const char* str1, const char* str2, int len){
182 assert (str1 != NULL && str2 != NULL);
183 assert ((len <= strlen(str1)) && (len <= strlen(str2)));
184 for (int i = 0 ; i < len; i++) {
185 if (str1[i] != str2[i]) {
186 if(isalpha(str1[i]) && isalpha(str2[i])
187 && (abs((str1[i]-str2[i])) == 32)) {
196 static bool isInThirdPartySOList(char* libName) {
197 assert (libName != NULL);
198 size_t libLen = strlen(libName);
199 size_t sz = thirdPartySO.size();
200 for (size_t i = 0; i < sz; i++) {
201 // thirdPartySO[i] won't be NULL
202 size_t n = strlen(thirdPartySO[i]);
203 // three char for ".so"
205 // now only '-' '-' and '.'found
206 while((j >= 0) && (isdigit(libName[j]) || (libName[j] == '-')
207 || (libName[j] == '_') || (libName[j] == '.'))) {
210 // three char for "lib" and include the name with no letters
211 if ((j == 2) || ((size_t)j == (n+2))) {
212 if (ignoreCmp(libName+3, thirdPartySO[i], n)) {
213 P_LOG("ABIpicker libName %s,In Third", libName);
222 static void insertionSort(Vector<char*>& list) {
223 P_LOG("in insertionSort, list size = %d\n", list.size());
225 for (size_t i = 1; i < list.size(); i++) {
229 P_LOG("sort 1. x=%s, i=%d, j=%d\n", x, i, j);
230 while (j >= 0 && (strcmp(list[j], x) > 0)) {
231 list.replaceAt(list[j], j + 1);
234 list.replaceAt(x, j + 1);
240 //////////////////////////////////////////////////////////////////////
241 // Use armRef as a reference, compare all libraries of iaRef with all
242 // libraries of armRef.If the two are match or iaRef is more, iaRef
243 // will be returned with *result and true is return value. Or else,
244 // *result is rawResult and false is return value
245 bool ABIPicker::compare(char* armRef, char* iaRef,
246 char* rawResult, char** result) {
251 assert(armRef != NULL);
252 if (0 == strlen(armRef)) {
253 *result = strlen(iaRef) > 0 ? iaRef : rawResult;
254 ret = strlen(iaRef) > 0 ? true : false;
257 assert(iaRef != NULL);
258 if (0 == strlen(iaRef)) {
264 Vector<char*>* iaRefList = getLibList(iaRef);
265 Vector<char*>* armRefList = getLibList(armRef);
267 // if contains the key words in iaRelated, just return true
268 assert(iaRefList != NULL);
269 assert(armRefList != NULL);
270 if (isReliableLib(*iaRefList)) {
275 if (compareLibList(*iaRefList, *armRefList)) {
280 size_t iaIsvLibCount = 0;
281 size_t armIsvLibCount = 0;
282 if (!compare3rdPartyLibList(iaRef, armRef,
283 &iaIsvLibCount, &armIsvLibCount)) {
289 if (iaIsvLibCount > 0) {
298 ALOGV("%s Vs. %s, return %s\n",
299 iaRef ? iaRef : "NULL",
300 armRef ? armRef : "NULL", *result);
304 bool ABIPicker::compareLibList(Vector<char*>& iaRefList,
305 Vector<char*>& armRefList) {
307 unsigned iaSize = iaRefList.size();
308 unsigned armSize = armRefList.size();
309 if (iaSize < armSize) {
311 } else if (iaSize == 0 && armSize == 0) {
317 Vector<char*>::iterator itIa = iaRefList.begin();
318 Vector<char*>::iterator itArm = armRefList.begin();
319 bool isEqual = false;
320 while (itIa != iaRefList.end() && itArm != armRefList.end()) {
321 if ((iaSize-iaNum) < (armSize-armNum)) {
325 char* armLibName = *itArm;
326 int armLen = strlen (armLibName);
329 while (itIa != iaRefList.end() && !isEqual) {
330 char* iaLibName = *itIa;
332 int iaLen = strlen (iaLibName);
333 if (iaLen == armLen) {
334 if (ignoreCmp(iaLibName, armLibName, iaLen)) {
342 // till the end, and the last result is equal
343 if (itArm == armRefList.end() && isEqual){
350 bool ABIPicker::compare3rdPartyLibList(
351 char* iaRef, char* armRef,
352 size_t* iaIsvLibCount, size_t* armIsvLibCount) {
353 Vector<char*>* iaRefList = getLibList(iaRef);
354 Vector<char*>* armRefList = getLibList(armRef);
355 assert(iaRefList != NULL);
356 assert(armRefList != NULL);
358 Vector<char*>* armRef3rdPartyLibList = new Vector<char*>();
359 Vector<char*>::iterator itArm = armRefList->begin();
363 getConfig(THIRDPARTY, thirdPartySO);
366 while (itArm != armRefList->end()) {
367 char* armLibName = *itArm;
368 if (isInThirdPartySOList(armLibName)) {
369 armRef3rdPartyLibList->push_back(armLibName);
377 Vector<char*>::iterator itIa = iaRefList->begin();
378 Vector<char*>* iaRef3rdPartyLibList = new Vector<char*>();
379 while (itIa != iaRefList->end()) {
380 char* iaLibName = *itIa;
381 if (isInThirdPartySOList(iaLibName)) {
382 iaRef3rdPartyLibList->push_back(iaLibName);
389 bool result = compareLibList(*iaRef3rdPartyLibList, *armRef3rdPartyLibList);
392 free(armRef3rdPartyLibList);
393 free(iaRef3rdPartyLibList);
397 char* ABIPicker::getAbiName(int abi) {
398 if (abi < 0 || (unsigned)abi >= mLibList->size()) {
404 Vector<struct libInfo*>::iterator it = mLibList->begin();
405 while (it != mLibList->end()) {
407 ret = (*it)->abiName;
418 int ABIPicker::getAbiIndex(const char* abiName) {
422 Vector<struct libInfo*>::iterator it = mLibList->begin();
423 while (it != mLibList->end()) {
424 if (0 == strcmp(abiName, (*it)->abiName)) {
436 Vector<char*>* ABIPicker::getLibList(const char* abiName) {
437 Vector<char*>* ret = NULL;
438 Vector<struct libInfo*>::iterator it = mLibList->begin();
439 while (it != mLibList->end()) {
440 if (0 == strcmp(abiName, (*it)->abiName)) {
441 ret = (*it)->libNameList;
446 P_LOG("getLibList of %s return %p\n", abiName, ret);
451 size_t ABIPicker::getSpecficABILibCount(const char* abiName) {
452 Vector<char*>* specificAbiLibList = getLibList(abiName);
453 return specificAbiLibList && specificAbiLibList->size();
456 bool ABIPicker::foundMixedELF(const char* abiName) {
457 Vector<char*>* libNameList = getLibList(abiName);
461 if (libNameList->size() == 0) {
465 if (0 != strcasecmp(*(libNameList->begin()), IMPOSSIBLE_LIB_NAME)) {
473 //////////////////////////////////////////////////////////////////////
474 ABIPicker::ABIPicker(const char* pkgName, Vector<ScopedUtfChars*> abiList) {
475 mLibList = new Vector<struct libInfo*>();
476 mpkgName = (char*)malloc(strlen(pkgName)+1);
478 P_LOG("ABIPicker Construct Allocated space fails");
480 snprintf(mpkgName, strlen(pkgName)+1, "%s", pkgName);
482 Vector<ScopedUtfChars*>::iterator it = abiList.begin();
483 while (it != abiList.end()) {
488 struct libInfo* tmp = (struct libInfo*)calloc(1,
489 sizeof(struct libInfo));
491 P_LOG("ABIPicker Construct Allocated space fail %s", (*it)->c_str());
495 snprintf(tmp->abiName, (*it)->size() + 1, "%s", (*it)->c_str());
496 tmp->libNameList = new Vector<char*>();
497 P_LOG("ABIPicker Construct %s , libNameList: %p",
498 tmp->abiName, tmp->libNameList);
499 mLibList->push_back(tmp);
504 ABIPicker::~ABIPicker(void) {
505 if(NULL != mpkgName) {
509 Vector<struct libInfo*>::iterator it = mLibList->begin();
510 while (it != mLibList->end()) {
511 freeAllString(*((*it)->libNameList));
512 (*it)->libNameList->clear();
513 delete (*it)->libNameList;
514 (*it)->libNameList = NULL;
524 bool ABIPicker::buildNativeLibList(void* apkHandle) {
528 ALOGE("apkHandle is NULL\n");
532 ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
534 if (!zipFile->startIteration(&cookie)) {
535 ALOGE("apk file is broken\n");
539 ZipEntryRO next = NULL;
540 char* unCompBuff = NULL;
541 char fileName[SO_NAME_MAX + 1];
542 while ((next = zipFile->nextEntry(cookie))) {
543 if (zipFile->getEntryFileName(next, fileName, SO_NAME_MAX)) {
544 ALOGE("apk file is broken, can not get entry name\n");
548 fileName[SO_NAME_MAX] = '\0';
550 // Make sure we're in the lib directory of the ZIP.
551 // find out entries with such names: "lib/xxxxxxx" or "lib/"
552 if (strncmp(fileName, APK_LIB, APK_LIB_LEN)) {
556 // find out any invalid ELF file
557 uint32_t unCompLen = 0;
558 if (!zipFile->getEntryInfo(next, NULL, &unCompLen, NULL, NULL, NULL,
560 ALOGE("apk file is broken, can not get entry info\n");
565 if (unCompLen == 0) {
566 ALOGV("skip a empty file(%s)\n", fileName);
575 unCompBuff = (char*)malloc(unCompLen);
577 ALOGE("malloc failed size %d\n", unCompLen);
581 memset(unCompBuff, 0, unCompLen);
582 // THE MOST TIME COST OPERATION
583 if (!zipFile->uncompressEntry(next, unCompBuff, unCompLen)) {
584 ALOGE("%s: uncompress failed\n", fileName);
589 if (!isValidELF(unCompBuff)) {
590 ALOGI("skip a fake .ELF file(%s)\n", fileName);
594 // It is a real .so file, prepare to record
595 // find abi name and focus on what we care: arm(s) and x86(s)
596 // at least lastSlash points to the end of "lib/"
597 const char* lastSlash = strrchr(fileName, '/');
598 const char* cpuAbiOffset = fileName + APK_LIB_LEN;
599 // just in case if fileName is in an abnormal format, like lib/libname,
601 if (lastSlash <= cpuAbiOffset) {
602 ALOGI("skip a invalid lib file(%s)\n", fileName);
606 const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset;
607 char curAbiName[ABI_NAME_MAX_LENGTH];
608 if (cpuAbiRegionSize >= ABI_NAME_MAX_LENGTH) {
611 snprintf(curAbiName, cpuAbiRegionSize + 1, "%s", cpuAbiOffset);
613 Vector<char*>* libListOfCurAbi = getLibList(curAbiName);
614 if (!libListOfCurAbi) {
615 P_LOG("getLibList of %s return NULL\n", curAbiName);
619 // mixed arm elf in lib/x86 or lib/x86_64
620 // but we don't consider a compareable scenario in lib/arm*
621 if (0 == strcmp(curAbiName, X86ABI) ||
622 0 == strcmp(curAbiName, X8664ABI)) {
623 if (!libListOfCurAbi->empty()) {
624 char* firstElement = libListOfCurAbi->itemAt(0);
625 if (0 == strcmp(firstElement, IMPOSSIBLE_LIB_NAME)) {
626 // won't add any new into the list if found mixed
628 P_LOG("won't count count if found mixed lib before");
633 if (isMixedLib(curAbiName, unCompBuff)) {
634 P_LOG("found mixed lib(%s) in lib/%s/", curAbiName, fileName);
635 freeAllString(*libListOfCurAbi);
636 libListOfCurAbi->clear();
637 char* mixedLib = (char*)malloc(IMPOSSIBLE_LIB_LEN+1);
639 ALOGE("malloc failed size %d", IMPOSSIBLE_LIB_LEN + 1);
643 snprintf(mixedLib, (IMPOSSIBLE_LIB_LEN+1), "%s", IMPOSSIBLE_LIB_NAME);
644 mixedLib[IMPOSSIBLE_LIB_LEN] ='\0';
645 libListOfCurAbi->push_back(mixedLib);
650 // now, lastSlash should point to lib name
652 const size_t libNameSize = strlen(lastSlash);
653 char* curLibName = (char*)malloc(libNameSize+1);
655 ALOGE("malloc failed size %d\n", libNameSize+1);
659 snprintf(curLibName,libNameSize+1, "%s", lastSlash);
660 curLibName[libNameSize] = '\0';
662 libListOfCurAbi->push_back(curLibName);
672 zipFile->endIteration(cookie);
674 for (unsigned i = 0; i < mLibList->size(); i++) {
675 struct libInfo* tmp = mLibList->itemAt(i);
676 insertionSort(*(tmp->libNameList));
681 int ABIPicker::pickupRightABI(int sysPrefer) {
682 char* sysPreferAbiName = getAbiName(sysPrefer);
683 if (!sysPreferAbiName) {
687 bool is64BitPrefer = (0 == strcmp(sysPreferAbiName, X8664ABI));
688 bool x8664HasMixedELF = foundMixedELF(X8664ABI);
689 bool x86HasMixedELF = foundMixedELF(X86ABI);
691 size_t armv7LibCount = getSpecficABILibCount(ARMV7ABI);
692 size_t armv5LibCount = getSpecficABILibCount(ARMABI);
693 size_t armv8LibCount = getSpecficABILibCount(ARM64ABI);
694 size_t x86LibCount = x86HasMixedELF ? 0 : getSpecficABILibCount(X86ABI);
695 size_t x8664LibCount = x8664HasMixedELF ? 0 : getSpecficABILibCount(X8664ABI);
696 P_LOG("armv7LibCount:%d armv5LibCount:%d armv8LibCount:%d x86LibCount:%d x8664LibCount:%d", armv7LibCount, armv5LibCount, armv8LibCount, x86LibCount, x8664LibCount);
698 // in OEMBlackList, need to be supported by bt
699 // but in case of armlib doesn't exist, we choose x86 or x86_64
700 if (isInOEMBlackList(mpkgName)) {
701 if (armv7LibCount > 0) {
702 return getAbiIndex(ARMV7ABI);
703 } else if (armv5LibCount > 0) {
704 return getAbiIndex(ARMABI);
705 } else if (armv8LibCount > 0) {
706 return getAbiIndex(ARM64ABI);
710 char arm64Ref[ABI_NAME_MAX_LENGTH];
711 if (armv8LibCount > 0) {
712 snprintf(arm64Ref, sizeof(ARM64ABI), "%s", ARM64ABI);
717 char arm32Ref[ABI_NAME_MAX_LENGTH];
718 if (armv7LibCount > 0) {
719 snprintf(arm32Ref, sizeof(ARMV7ABI), "%s", ARMV7ABI);
720 } else if (armv5LibCount > 0) {
721 snprintf(arm32Ref, sizeof(ARMABI), "%s", ARMABI);
726 char ia32Ref[ABI_NAME_MAX_LENGTH];
727 if (x86LibCount > 0) {
728 snprintf(ia32Ref, sizeof(X86ABI), "%s", X86ABI);
733 char ia64Ref[ABI_NAME_MAX_LENGTH];
734 if (x8664LibCount > 0) {
735 snprintf(ia64Ref, ABI_NAME_MAX_LENGTH, "%s", X8664ABI);
740 char* retAbiName = sysPreferAbiName;
742 // # The basic rule is:
743 // - on 32 bit system, compare ia32Ref native libraries with
744 // arm32Ref native libraries. If pass, return ia32Ref .
745 // If fail, return arm32Ref.
746 // - on 64 bit system, IA has two chances. if ia64Ref native
747 // libraries can't pass the comparation with arm64Ref, we should
748 // run the comparation again with ia32Ref
750 if (!compare(arm64Ref, ia64Ref, sysPreferAbiName, &retAbiName)) {
751 char rawRes[ABI_NAME_MAX_LENGTH];
752 snprintf(rawRes, ABI_NAME_MAX_LENGTH, "%s", retAbiName);
753 compare(arm32Ref, ia32Ref, rawRes, &retAbiName);
756 compare(arm32Ref, ia32Ref, sysPreferAbiName, &retAbiName);
759 int ret = getAbiIndex(retAbiName);
760 ALOGI("selected abi %s(%d) for %s", retAbiName, ret, mpkgName);
764 } // namespace android