apex: only mount required apex files

Since recent kernels seem to limit the number of loopback
devices to 7, we now just mount the required apex files in TWRP.

To mount additional apex files specify TW_ADDITIONAL_APEX_FILES
in your BoardConfig, for example:
TW_ADDITIONAL_APEX_FILES := "apex1 apex2"

To disable Apex in your builds use:
TW_EXLUCDE_APEX := true
Change-Id: Ib55529a4dc17ce2b737b01b86100dca3dc75e6c9

Change-Id: I3b4dfbb164838ffb126016b0d862f67d3f170bf3
diff --git a/Android.mk b/Android.mk
index 038daaa..c7998ac 100755
--- a/Android.mk
+++ b/Android.mk
@@ -71,9 +71,14 @@
     openrecoveryscript.cpp \
     tarWrite.c \
     twrpAdbBuFifo.cpp \
-    twrpApex.cpp \
     twrpRepacker.cpp
 
+ifeq ($(TW_EXCLUDE_APEX),)
+    LOCAL_SRC_FILES += twrpApex.cpp
+else
+    LOCAL_CFLAGS += -DTW_EXCLUDE_APEX
+endif
+
 LOCAL_STATIC_LIBRARIES += libavb libtwrpinstall libminadbd_services libinit
 LOCAL_SHARED_LIBRARIES += libfs_mgr
 LOCAL_C_INCLUDES += \
@@ -284,6 +289,9 @@
 ifeq ($(TW_INCLUDE_L_CRYPTO), true)
     TW_INCLUDE_CRYPTO := true
 endif
+ifneq ($(TW_ADDITIONAL_APEX_FILES),)
+    LOCAL_CFLAGS += -DTW_ADDITIONAL_APEX_FILES=$(TW_ADDITIONAL_APEX_FILES)
+endif
 ifeq ($(TW_INCLUDE_CRYPTO), true)
     LOCAL_CFLAGS += -DTW_INCLUDE_CRYPTO -DUSE_FSCRYPT -Wno-macro-redefined
     LOCAL_SHARED_LIBRARIES += libcryptfsfde
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 9a30249..158d916 100755
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -292,6 +292,9 @@
 			if (ven) {
 				ven->Mount(true);
 			}
+#ifdef TW_EXCLUDE_APEX
+			LOGINFO("Apex is disabled in this build\n");
+#else
 			twrpApex apex;
 			if (!apex.loadApexImages()) {
 				LOGERR("Unable to load apex images from %s\n", APEX_DIR);
@@ -300,6 +303,7 @@
 				property_set("twrp.apex.loaded", "true");
 			}
 			TWFunc::check_and_run_script("/sbin/resyncapex.sh", "apex");
+#endif
 		}
 	}
 #ifndef USE_VENDOR_LIBS
diff --git a/twrpApex.cpp b/twrpApex.cpp
index 52dd9e5..45e3e30 100755
--- a/twrpApex.cpp
+++ b/twrpApex.cpp
@@ -1,21 +1,44 @@
 #include "twrpApex.hpp"
 #include "twrp-functions.hpp"
+#include "common.h"
 
 namespace fs = std::filesystem;
 
 bool twrpApex::loadApexImages() {
 	std::vector<std::string> apexFiles;
+	std::vector<std::string> checkApexFlatFiles;
+#ifdef TW_ADDITIONAL_APEX_FILES
+	char* additionalFiles = strdup(EXPAND(TW_ADDITIONAL_APEX_FILES));
+	char* additionalApexFiles = std::strtok(additionalFiles, " ");
+#endif
+
+	apexFiles.push_back(APEX_DIR "/com.android.apex.cts.shim.apex");
+	apexFiles.push_back(APEX_DIR "/com.google.android.tzdata2.apex");
+	apexFiles.push_back(APEX_DIR "/com.android.tzdata.apex");
+	apexFiles.push_back(APEX_DIR "/com.android.art.release.apex");
+	apexFiles.push_back(APEX_DIR "/com.google.android.media.swcodec.apex");
+	apexFiles.push_back(APEX_DIR "/com.android.media.swcodec.apex");
+
+#ifdef TW_ADDITIONAL_APEX_FILES
+	while(additionalApexFiles) {
+		std::stringstream apexFile;
+		apexFile << APEX_DIR << "/" << additionalApexFiles;
+		apexFiles.push_back(apexFile.str());
+		additionalApexFiles = std::strtok(nullptr, " ");
+	}
+#endif
+
 	if (access(APEX_DIR, F_OK) != 0) {
 		LOGERR("Unable to open %s\n", APEX_DIR);
 		return false;
 	}
 	for (const auto& entry : fs::directory_iterator(APEX_DIR)) {
 	   if (entry.is_regular_file()) {
-		   apexFiles.push_back(entry.path().string());
+		   checkApexFlatFiles.push_back(entry.path().string());
 	   }
 	}
 
-	if (apexFiles.size() == 0) {
+	if (checkApexFlatFiles.size() == 0) {
 		// flattened apex directory
 		LOGINFO("Bind mounting flattened apex directory\n");
 		if (mount(APEX_DIR, APEX_BASE, "", MS_BIND, NULL) < 0) {
@@ -36,9 +59,8 @@
 	ZipArchiveHandle handle;
 	int32_t ret = OpenArchive(file.c_str(), &handle);
 	if (ret != 0) {
-		LOGERR("unable to open zip archive %s\n", file.c_str());
-		CloseArchive(handle);
-		return nullptr;
+		LOGINFO("unable to open zip archive %s. Reason: %s\n", file.c_str(), strerror(errno));
+		return std::string();
 	}
 
 	ZipEntry entry;
@@ -47,7 +69,7 @@
 	if (ret != 0) {
 		LOGERR("unable to find %s in zip\n", APEX_PAYLOAD);
 		CloseArchive(handle);
-		return nullptr;
+		return std::string();
 	}
 
 	std::string baseFile = basename(file.c_str());
@@ -59,7 +81,7 @@
 		LOGERR("unable to extract %s\n", path.c_str());
 		close(fd);
 		CloseArchive(handle);
-		return nullptr;
+		return std::string();
 	}
 
 	CloseArchive(handle);
@@ -87,6 +109,10 @@
 			}
 		}
 		std::string fileToMount = unzipImage(apexFile);
+		if (fileToMount.empty()) {
+			LOGINFO("Skipping non-existent apex file: %s\n", apexFile.c_str());
+			continue;
+		}
 		bool load_result = loadApexImage(fileToMount, device_no);
 		if (!load_result) {
 			return false;
@@ -114,7 +140,8 @@
 	}
 
 	if (ioctl(loop_fd, LOOP_SET_FD, fd) < 0) {
-		LOGERR("failed to mount %s to loop device %s\n", fileToMount.c_str(), loop_device.c_str());
+		LOGERR("failed to mount %s to loop device %s. Reason: %s\n", fileToMount.c_str(), loop_device.c_str(), 
+			strerror(errno));
 		close(fd);
 		close(loop_fd);
 		return false;
diff --git a/twrpApex.hpp b/twrpApex.hpp
index f42ed8a..edd1d5f 100755
--- a/twrpApex.hpp
+++ b/twrpApex.hpp
@@ -5,6 +5,7 @@
 #include <string>
 #include <vector>
 #include <filesystem>
+#include <sstream>
 
 #include <sys/types.h>
 #include <sys/stat.h>