[incfs] Make native library extraction async

IncrementalService can create the library files beforehand, but
delay filling in their data. As it takes quite a while in
general (over a second in cases when the phone is busy), it's
better to run the unzipping and filling in a separate thread
and only make sure it finishes before the whole installation
process is complete.
This speeds up the megacity.apk installation by ~250-300ms,
1000-1100ms -> 750-800ms

Bug: 153513507
Test: adb install megacity.apk

Change-Id: Ia44f7e45b9e0abaebdfb6fe5352f9dcf29ab4ece
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 27d40f1..4fdce4b 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -23,16 +23,19 @@
 #include <utils/String16.h>
 #include <utils/StrongPointer.h>
 #include <utils/Vector.h>
+#include <ziparchive/zip_archive.h>
 
 #include <atomic>
 #include <chrono>
-#include <future>
+#include <condition_variable>
+#include <functional>
 #include <limits>
 #include <map>
 #include <mutex>
 #include <span>
 #include <string>
 #include <string_view>
+#include <thread>
 #include <unordered_map>
 #include <utility>
 #include <vector>
@@ -132,12 +135,15 @@
 
     std::vector<std::string> listFiles(StorageId storage) const;
     bool startLoading(StorageId storage) const;
+
     bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
                                  std::string_view libDirRelativePath, std::string_view abi);
+    bool waitForNativeBinariesExtraction(StorageId storage);
 
     class AppOpsListener : public android::BnAppOpsCallback {
     public:
-        AppOpsListener(IncrementalService& incrementalService, std::string packageName) : incrementalService(incrementalService), packageName(std::move(packageName)) {}
+        AppOpsListener(IncrementalService& incrementalService, std::string packageName)
+              : incrementalService(incrementalService), packageName(std::move(packageName)) {}
         void opChanged(int32_t op, const String16& packageName) final;
 
     private:
@@ -277,7 +283,12 @@
     bool unregisterAppOpsCallback(const std::string& packageName);
     void onAppOpChanged(const std::string& packageName);
 
-    // Member variables
+    void runJobProcessing();
+    void extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile, ZipEntry& entry,
+                        const incfs::FileId& libFileId, std::string_view targetLibPath,
+                        Clock::time_point scheduledTs);
+
+private:
     std::unique_ptr<VoldServiceWrapper> const mVold;
     std::unique_ptr<DataLoaderManagerWrapper> const mDataLoaderManager;
     std::unique_ptr<IncFsWrapper> const mIncFs;
@@ -294,6 +305,14 @@
 
     std::atomic_bool mSystemReady = false;
     StorageId mNextId = 0;
+
+    using Job = std::function<void()>;
+    std::unordered_map<StorageId, std::vector<Job>> mJobQueue;
+    StorageId mPendingJobsStorage = kInvalidStorageId;
+    std::condition_variable mJobCondition;
+    std::mutex mJobMutex;
+    std::thread mJobProcessor;
+    bool mRunning = true;
 };
 
 } // namespace android::incremental