1 #define LOG_TAG "ABIPicker"
3 #include "abipicker/ABIPicker.h"
4 #include "abipicker/ELFLite.h"
6 #include <androidfw/ZipFileRO.h>
7 #include <androidfw/ZipUtils.h>
11 #define ARR_SIZE(x) (sizeof(x)/sizeof(x[0]))
13 #define SO_NAME_MAX (4096)
15 #define IMPOSSIBLE_LIB_NAME "/mixed/"
16 #define IMPOSSIBLE_LIB_LEN (sizeof(IMPOSSIBLE_LIB_NAME)-1)
18 #define ARMABI "armeabi"
19 #define ARMV7ABI "armeabi-v7a"
20 #define ARM64ABI "arm64-v8a"
22 #define X8664ABI "x86_64"
24 #define APK_LIB "lib/"
25 #define APK_LIB_LEN (sizeof(APK_LIB) - 1)
26 //#define PICK_LOGGER //flag to debug
28 #define P_LOG(...) ALOGI(__VA_ARGS__)
33 #define LISTPATH "/vendor/etc/misc/"
34 #define OEMWHITE LISTPATH ".OEMWhiteList"
35 #define OEMBLACK LISTPATH ".OEMBlackList"
36 #define THIRDPARTY LISTPATH ".ThirdPartySO"
38 // load once, hold until poweroff
39 static Vector <char*> thirdPartySO;
40 static Vector <char*> cfgWhite;
41 static Vector <char*> cfgBlack;
42 static bool thirdload = false;
43 static bool whiteload = false;
44 static bool blackload = false;
46 static const char* iaRelated[] = {"intel", "intl", "atom", "x86", "x64"};
48 void freeAllString(Vector<char*>& list) {
49 Vector<char*>::iterator it = list.begin();
50 while (it != list.end()) {
52 P_LOG("freeAllSring %p , %s", it, *it);
60 void getConfig(const char* cfgFile , Vector<char*>& cfgVec) {
65 FILE* fp = fopen(cfgFile, "r");
70 freeAllString(cfgVec);
73 while ((read = getline(&line, &len, fp)) != -1) {
75 char *cfgline = (char*)malloc(len);
76 if (cfgline == NULL) {
77 P_LOG("malloc error");
80 for (i = 0; i < read; i++) {
81 if (!isspace(line[i])) {
82 cfgline[j++] = line[i];
86 cfgVec.push_back(cfgline);
87 P_LOG("orignal %s , vec: %s ", line, cfgline);
93 bool isInOEMWhiteList(const char* pkgName) {
95 if (pkgName == NULL) {
100 getConfig(OEMWHITE, cfgWhite);
104 Vector<char*>::iterator it = cfgWhite.begin();
105 for (; it != cfgWhite.end(); it++) {
106 P_LOG("whitelist : %s", *it);
107 if (0 == fnmatch(*it, pkgName, 0)) {
108 ALOGI("whitelist %s by %s", pkgName, *it);
116 bool isInOEMBlackList(const char* pkgName) {
118 if (pkgName == NULL) {
123 getConfig(OEMBLACK, cfgBlack);
127 Vector<char*>::iterator it = cfgBlack.begin();
128 for (; it != cfgBlack.end(); it++) {
129 if (0 == fnmatch(*it, pkgName, 0)) {
130 ALOGI("blacklist %s by %s", pkgName, *it);
138 bool isReliableLib(Vector<char*>& libList) {
139 unsigned sz = libList.size();
140 int len = ARR_SIZE(iaRelated);
141 for (unsigned i = 0; i < sz; i++) {
142 for (int j=0; j < len; j++) {
144 if (NULL != (p = strcasestr(libList[i], iaRelated[j]))) {
145 int lenIA = strlen(iaRelated[j]);
146 if (!isalpha(*(p+lenIA))) {
147 if (!isalpha(*(p-1)) || (p == (libList[i] + 3))) {
158 static bool isValidELF(char* buffer) {
159 if (buffer[EI_MAG0] != ELFMAG0 &&
160 buffer[EI_MAG1] != ELFMAG1 &&
161 buffer[EI_MAG2] != ELFMAG2 &&
162 buffer[EI_MAG3] != ELFMAG3) {
168 // assume that x86 has the only machine-code 3, and x86_64 62
169 static bool isMixedLib(char* libCur, char* buffer) {
170 bool isX86_64 = (0 == strcmp(libCur, X8664ABI)) ? true: false;
171 uint16_t machine_code = *((uint16_t*)(&buffer[ELF_MACHINE_OFFSET]));
174 if (machine_code != EM_X86_64) {
178 if (machine_code != EM_386) {
185 // compare the given string with the length, igonre upper and lower
186 // len must be less than the length of two string
187 static bool ignoreCmp(const char* str1, const char* str2, int len){
188 assert (str1 != NULL && str2 != NULL);
189 assert ((len <= strlen(str1)) && (len <= strlen(str2)));
190 for (int i = 0 ; i < len; i++) {
191 if (str1[i] != str2[i]) {
192 if(isalpha(str1[i]) && isalpha(str2[i])
193 && (abs((str1[i]-str2[i])) == 32)) {
202 static bool isInThirdPartySOList(char* libName) {
203 assert (libName != NULL);
204 size_t libLen = strlen(libName);
205 size_t sz = thirdPartySO.size();
206 for (size_t i = 0; i < sz; i++) {
207 // thirdPartySO[i] won't be NULL
208 assert(thirdPartySO[i] != NULL);
209 size_t n = strlen(thirdPartySO[i]);
210 // three char for ".so"
212 // now only '-' '-' and '.'found
213 while((j >= 0) && (isdigit(libName[j]) || (libName[j] == '-')
214 || (libName[j] == '_') || (libName[j] == '.'))) {
217 // three char for "lib" and include the name with no letters
218 if ((j == 2) || ((size_t)j == (n+2))) {
219 if (ignoreCmp(libName+3, thirdPartySO[i], n)) {
220 P_LOG("ABIpicker libName %s,In Third", libName);
229 static void insertionSort(Vector<char*>& list) {
230 P_LOG("in insertionSort, list size = %d\n", list.size());
232 for (size_t i = 1; i < list.size(); i++) {
235 P_LOG("sort 1. x=%s, i=%d, j=%d\n", x, i, j);
236 while (j >= 0 && (strcmp(list[j], x) > 0)) {
237 list.replaceAt(list[j], j + 1);
240 list.replaceAt(x, j + 1);
244 // Use armRef as a reference, compare all libraries of iaRef with all
245 // libraries of armRef.If the two are match or iaRef is more, iaRef
246 // will be returned with *result and true is return value. Or else,
247 // *result is rawResult and false is return value
248 bool ABIPicker::compare(char* armRef, char* iaRef,
249 char* rawResult, char** result) {
254 assert(armRef != NULL);
255 if (0 == strlen(armRef)) {
256 *result = strlen(iaRef) > 0 ? iaRef : rawResult;
257 ret = strlen(iaRef) > 0 ? true : false;
260 assert(iaRef != NULL);
261 if (0 == strlen(iaRef)) {
267 Vector<char*>* iaRefList = getLibList(iaRef);
268 Vector<char*>* armRefList = getLibList(armRef);
269 if (iaRefList == NULL || armRefList == NULL) {
273 if (isReliableLib(*iaRefList)) {
278 if (compareLibList(*iaRefList, *armRefList)) {
283 size_t iaIsvLibCount = 0;
284 size_t armIsvLibCount = 0;
285 if (!compare3rdPartyLibList(iaRef, armRef,
286 &iaIsvLibCount, &armIsvLibCount)) {
292 if (iaIsvLibCount > 0) {
301 ALOGV("%s Vs. %s, return %s\n",
302 iaRef ? iaRef : "NULL",
303 armRef ? armRef : "NULL", *result);
307 bool ABIPicker::compareLibList(Vector<char*>& iaRefList,
308 Vector<char*>& armRefList) {
310 unsigned iaSize = iaRefList.size();
311 unsigned armSize = armRefList.size();
312 if (iaSize < armSize) {
314 } else if (iaSize == 0 && armSize == 0) {
320 Vector<char*>::iterator itIa = iaRefList.begin();
321 Vector<char*>::iterator itArm = armRefList.begin();
322 bool isEqual = false;
323 while (itIa != iaRefList.end() && itArm != armRefList.end()) {
324 if ((iaSize-iaNum) < (armSize-armNum)) {
328 char* armLibName = *itArm;
329 int armLen = strlen (armLibName);
332 while (itIa != iaRefList.end() && !isEqual) {
333 char* iaLibName = *itIa;
335 int iaLen = strlen (iaLibName);
336 if (iaLen == armLen) {
337 if (ignoreCmp(iaLibName, armLibName, iaLen)) {
345 // till the end, and the last result is equal
346 if (itArm == armRefList.end() && isEqual){
353 bool ABIPicker::compare3rdPartyLibList(
354 char* iaRef, char* armRef,
355 size_t* iaIsvLibCount, size_t* armIsvLibCount) {
358 Vector<char*>* iaRefList = getLibList(iaRef);
359 Vector<char*>* armRefList = getLibList(armRef);
360 if (iaRefList == NULL || armRefList == NULL) {
365 getConfig(THIRDPARTY, thirdPartySO);
369 Vector<char*>* armRef3rdPartyLibList = new Vector<char*>();
370 Vector<char*>::iterator itArm = armRefList->begin();
371 while (itArm != armRefList->end()) {
372 char* armLibName = *itArm;
373 if (isInThirdPartySOList(armLibName)) {
374 armRef3rdPartyLibList->push_back(armLibName);
382 Vector<char*>::iterator itIa = iaRefList->begin();
383 Vector<char*>* iaRef3rdPartyLibList = new Vector<char*>();
384 while (itIa != iaRefList->end()) {
385 char* iaLibName = *itIa;
386 if (isInThirdPartySOList(iaLibName)) {
387 iaRef3rdPartyLibList->push_back(iaLibName);
394 result = compareLibList(*iaRef3rdPartyLibList, *armRef3rdPartyLibList);
396 armRef3rdPartyLibList->clear();
397 delete armRef3rdPartyLibList;
398 iaRef3rdPartyLibList->clear();
399 delete iaRef3rdPartyLibList;
403 char* ABIPicker::getAbiName(int abi) {
404 if (abi < 0 || (unsigned)abi >= mLibList->size()) {
410 Vector<struct libInfo*>::iterator it = mLibList->begin();
411 while (it != mLibList->end()) {
413 ret = (*it)->abiName;
424 int ABIPicker::getAbiIndex(const char* abiName) {
428 Vector<struct libInfo*>::iterator it = mLibList->begin();
429 while (it != mLibList->end()) {
430 if (0 == strcmp(abiName, (*it)->abiName)) {
442 Vector<char*>* ABIPicker::getLibList(const char* abiName) {
443 Vector<char*>* ret = NULL;
444 Vector<struct libInfo*>::iterator it = mLibList->begin();
445 while (it != mLibList->end()) {
446 if (0 == strcmp(abiName, (*it)->abiName)) {
447 ret = (*it)->libNameList;
452 P_LOG("getLibList of %s return %p\n", abiName, ret);
457 bool ABIPicker::isABILibValid(const char* abiName) {
458 Vector<char*>* specificAbiLibList = getLibList(abiName);
459 return ((specificAbiLibList && specificAbiLibList->size()) > 0);
462 bool ABIPicker::foundMixedELF(const char* abiName) {
463 Vector<char*>* libNameList = getLibList(abiName);
467 if (libNameList->size() == 0) {
471 if (0 != strcasecmp(*(libNameList->begin()), IMPOSSIBLE_LIB_NAME)) {
478 ABIPicker::ABIPicker(const char* pkgName, Vector<ScopedUtfChars*> abiList) {
479 mLibList = new Vector<struct libInfo*>();
480 mpkgName = strdup(pkgName);
481 if (mpkgName == NULL) {
482 P_LOG("ABIPicker Construct Allocated space fails");
484 Vector<ScopedUtfChars*>::iterator it = abiList.begin();
485 while (it != abiList.end()) {
490 struct libInfo* tmp = (struct libInfo*)calloc(1,
491 sizeof(struct libInfo));
493 P_LOG("ABIPicker Construct Allocated space fail %s", (*it)->c_str());
497 snprintf(tmp->abiName, (*it)->size() + 1, "%s", (*it)->c_str());
498 tmp->libNameList = new Vector<char*>();
499 P_LOG("ABIPicker Construct %s , libNameList: %p",
500 tmp->abiName, tmp->libNameList);
501 mLibList->push_back(tmp);
506 ABIPicker::~ABIPicker(void) {
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) {
527 if (apkHandle == NULL) {
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);
573 unCompBuff = (char*)malloc(unCompLen);
574 if (unCompBuff == NULL) {
575 ALOGE("malloc failed size %d\n", unCompLen);
579 memset(unCompBuff, 0, unCompLen);
580 // THE MOST TIME COST OPERATION
581 if (!zipFile->uncompressEntry(next, unCompBuff, unCompLen)) {
582 ALOGE("%s: uncompress failed\n", fileName);
587 if (!isValidELF(unCompBuff)) {
588 ALOGI("skip a fake .ELF file(%s)\n", fileName);
592 // It is a real .so file, prepare to record
593 // find abi name and focus on what we care: arm(s) and x86(s)
594 // at least lastSlash points to the end of "lib/"
595 const char* lastSlash = strrchr(fileName, '/');
596 const char* cpuAbiOffset = fileName + APK_LIB_LEN;
597 // just in case if fileName is in an abnormal format, like lib/libname,
599 if (lastSlash <= cpuAbiOffset) {
600 ALOGI("skip a invalid lib file(%s)\n", fileName);
604 const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset;
605 char curAbiName[ABI_NAME_MAX_LENGTH];
606 if (cpuAbiRegionSize >= ABI_NAME_MAX_LENGTH) {
609 snprintf(curAbiName, cpuAbiRegionSize + 1, "%s", cpuAbiOffset);
611 Vector<char*>* libListOfCurAbi = getLibList(curAbiName);
612 if (!libListOfCurAbi) {
613 P_LOG("getLibList of %s return NULL\n", curAbiName);
617 // mixed arm elf in lib/x86 or lib/x86_64
618 // but we don't consider a compareable scenario in lib/arm*
619 if (0 == strcmp(curAbiName, X86ABI) ||
620 0 == strcmp(curAbiName, X8664ABI)) {
621 if (!libListOfCurAbi->empty()) {
622 char* firstElement = libListOfCurAbi->itemAt(0);
623 if (0 == strcmp(firstElement, IMPOSSIBLE_LIB_NAME)) {
624 // won't add any new into the list if found mixed
626 P_LOG("won't count count if found mixed lib before");
631 if (isMixedLib(curAbiName, unCompBuff)) {
632 P_LOG("found mixed lib(%s) in lib/%s/", curAbiName, fileName);
633 freeAllString(*libListOfCurAbi);
634 libListOfCurAbi->clear();
635 char* mixedLib = (char*)malloc(IMPOSSIBLE_LIB_LEN+1);
637 ALOGE("malloc failed size %zu", IMPOSSIBLE_LIB_LEN + 1);
641 snprintf(mixedLib, (IMPOSSIBLE_LIB_LEN+1), "%s", IMPOSSIBLE_LIB_NAME);
642 mixedLib[IMPOSSIBLE_LIB_LEN] ='\0';
643 libListOfCurAbi->push_back(mixedLib);
648 // now, lastSlash should point to lib name
650 const size_t libNameSize = strlen(lastSlash);
651 char* curLibName = (char*)malloc(libNameSize+1);
653 ALOGE("malloc failed size %zu\n", libNameSize+1);
657 snprintf(curLibName,libNameSize+1, "%s", lastSlash);
658 curLibName[libNameSize] = '\0';
660 libListOfCurAbi->push_back(curLibName);
668 zipFile->endIteration(cookie);
670 for (unsigned i = 0; i < mLibList->size(); i++) {
671 struct libInfo* tmp = mLibList->itemAt(i);
672 insertionSort(*(tmp->libNameList));
677 int ABIPicker::pickupRightABI(int sysPrefer) {
678 char* sysPreferAbiName = getAbiName(sysPrefer);
679 if (!sysPreferAbiName) {
683 bool is64BitPrefer = (0 == strcmp(sysPreferAbiName, X8664ABI));
684 bool x8664HasMixedELF = foundMixedELF(X8664ABI);
685 bool x86HasMixedELF = foundMixedELF(X86ABI);
687 bool armv7LibValid = isABILibValid(ARMV7ABI);
688 bool armv5LibValid = isABILibValid(ARMABI);
689 bool armv8LibValid = isABILibValid(ARM64ABI);
690 bool x86LibValid = x86HasMixedELF ? 0 : isABILibValid(X86ABI);
691 bool x8664LibValid = x8664HasMixedELF ? 0 : isABILibValid(X8664ABI);
693 // in OEMBlackList, need to be supported by bt
694 // but in case of armlib doesn't exist, we choose x86 or x86_64
695 if (isInOEMBlackList(mpkgName)) {
697 return getAbiIndex(ARMV7ABI);
698 } else if (armv5LibValid) {
699 return getAbiIndex(ARMABI);
700 } else if (armv8LibValid) {
701 return getAbiIndex(ARM64ABI);
705 char arm64Ref[ABI_NAME_MAX_LENGTH];
707 snprintf(arm64Ref, sizeof(ARM64ABI), "%s", ARM64ABI);
712 char arm32Ref[ABI_NAME_MAX_LENGTH];
714 snprintf(arm32Ref, sizeof(ARMV7ABI), "%s", ARMV7ABI);
715 } else if (armv5LibValid) {
716 snprintf(arm32Ref, sizeof(ARMABI), "%s", ARMABI);
721 char ia32Ref[ABI_NAME_MAX_LENGTH];
723 snprintf(ia32Ref, sizeof(X86ABI), "%s", X86ABI);
728 char ia64Ref[ABI_NAME_MAX_LENGTH];
730 snprintf(ia64Ref, ABI_NAME_MAX_LENGTH, "%s", X8664ABI);
735 char* retAbiName = sysPreferAbiName;
737 // # The basic rule is:
738 // - on 32 bit system, compare ia32Ref native libraries with
739 // arm32Ref native libraries. If pass, return ia32Ref .
740 // If fail, return arm32Ref.
741 // - on 64 bit system, IA has two chances. if ia64Ref native
742 // libraries can't pass the comparation with arm64Ref, we should
743 // run the comparation again with ia32Ref
745 if (!compare(arm64Ref, ia64Ref, sysPreferAbiName, &retAbiName)) {
746 char rawRes[ABI_NAME_MAX_LENGTH];
747 snprintf(rawRes, ABI_NAME_MAX_LENGTH, "%s", retAbiName);
748 compare(arm32Ref, ia32Ref, rawRes, &retAbiName);
751 compare(arm32Ref, ia32Ref, sysPreferAbiName, &retAbiName);
754 int ret = getAbiIndex(retAbiName);
755 ALOGI("selected abi %s(%d) for %s", retAbiName, ret, mpkgName);
759 } // namespace android