Merge "Switch to C23's memset_explicit()."
diff --git a/Android.bp b/Android.bp
index 69907b6..1ccfc09 100644
--- a/Android.bp
+++ b/Android.bp
@@ -168,7 +168,7 @@
         "libkeymint_support",
     ],
     whole_static_libs: [
-        "com.android.sysprop.apex",
+        "libcom.android.sysprop.apex",
         "libc++fs",
     ],
 }
@@ -190,7 +190,7 @@
     required: [
         "mke2fs",
         "vold_prepare_subdirs",
-        "fuse_media.o",
+        "fuseMedia.o",
     ],
 
     shared_libs: [
diff --git a/IdleMaint.cpp b/IdleMaint.cpp
index b1565aa..d0a3a4c 100644
--- a/IdleMaint.cpp
+++ b/IdleMaint.cpp
@@ -530,9 +530,10 @@
 }
 
 void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate,
-                     float reclaimWeight, int32_t gcPeriod, int32_t minGCSleepTime) {
+                     float reclaimWeight, int32_t gcPeriod, int32_t minGCSleepTime,
+                     int32_t targetDirtyRatio) {
     std::list<std::string> paths;
-    bool needGC = true;
+    bool needGC = false;
     int32_t sleepTime;
 
     addFromFstab(&paths, PathTypes::kBlkDevice, true);
@@ -575,25 +576,36 @@
     int32_t reservedBlocks = std::stoi(ovpSegmentsStr) + std::stoi(reservedBlocksStr);
 
     freeSegments = freeSegments > reservedBlocks ? freeSegments - reservedBlocks : 0;
-    neededSegments *= reclaimWeight;
-    if (freeSegments >= neededSegments) {
-        LOG(INFO) << "Enough free segments: " << freeSegments
-                   << ", needed segments: " << neededSegments;
-        needGC = false;
-    } else if (freeSegments + dirtySegments < minSegmentThreshold) {
+    int32_t totalSegments = freeSegments + dirtySegments;
+    int32_t finalTargetSegments = 0;
+
+    if (totalSegments < minSegmentThreshold) {
         LOG(INFO) << "The sum of free segments: " << freeSegments
-                   << ", dirty segments: " << dirtySegments << " is under " << minSegmentThreshold;
-        needGC = false;
+                  << ", dirty segments: " << dirtySegments << " is under " << minSegmentThreshold;
     } else {
-        neededSegments -= freeSegments;
-        neededSegments = std::min(neededSegments, (int32_t)(dirtySegments * dirtyReclaimRate));
-        if (neededSegments == 0) {
-            LOG(INFO) << "Low dirty segments: " << dirtySegments;
-            needGC = false;
+        int32_t dirtyRatio = dirtySegments * 100 / totalSegments;
+        int32_t neededForTargetRatio =
+                (dirtyRatio > targetDirtyRatio)
+                        ? totalSegments * (dirtyRatio - targetDirtyRatio) / 100
+                        : 0;
+        neededSegments *= reclaimWeight;
+        neededSegments = (neededSegments > freeSegments) ? neededSegments - freeSegments : 0;
+
+        finalTargetSegments = std::max(neededSegments, neededForTargetRatio);
+        if (finalTargetSegments == 0) {
+            LOG(INFO) << "Enough free segments: " << freeSegments;
         } else {
-            sleepTime = gcPeriod * ONE_MINUTE_IN_MS / neededSegments;
-            if (sleepTime < minGCSleepTime) {
-                sleepTime = minGCSleepTime;
+            finalTargetSegments =
+                    std::min(finalTargetSegments, (int32_t)(dirtySegments * dirtyReclaimRate));
+            if (finalTargetSegments == 0) {
+                LOG(INFO) << "Low dirty segments: " << dirtySegments;
+            } else if (neededSegments >= neededForTargetRatio) {
+                LOG(INFO) << "Trigger GC, because of needed segments exceeding free segments";
+                needGC = true;
+            } else {
+                LOG(INFO) << "Trigger GC for target dirty ratio diff of: "
+                          << dirtyRatio - targetDirtyRatio;
+                needGC = true;
             }
         }
     }
@@ -605,6 +617,11 @@
         return;
     }
 
+    sleepTime = gcPeriod * ONE_MINUTE_IN_MS / finalTargetSegments;
+    if (sleepTime < minGCSleepTime) {
+        sleepTime = minGCSleepTime;
+    }
+
     if (!WriteStringToFile(std::to_string(sleepTime), gcSleepTimePath)) {
         PLOG(WARNING) << "Writing failed in " << gcSleepTimePath;
         return;
@@ -616,8 +633,8 @@
     }
 
     LOG(INFO) << "Successfully set gc urgent mode: "
-               << "free segments: " << freeSegments << ", reclaim target: " << neededSegments
-               << ", sleep time: " << sleepTime;
+              << "free segments: " << freeSegments << ", reclaim target: " << finalTargetSegments
+              << ", sleep time: " << sleepTime;
 }
 
 static int32_t getLifeTimeWrite() {
diff --git a/IdleMaint.h b/IdleMaint.h
index e94f853..a28cde2 100644
--- a/IdleMaint.h
+++ b/IdleMaint.h
@@ -27,7 +27,8 @@
 int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
 int32_t GetStorageLifeTime();
 void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate,
-                     float reclaimWeight, int32_t gcPeriod, int32_t minGCSleepTime);
+                     float reclaimWeight, int32_t gcPeriod, int32_t minGCSleepTime,
+                     int32_t targetDirtyRatio);
 void RefreshLatestWrite();
 int32_t GetWriteAmount();
 
diff --git a/KeyStorage.cpp b/KeyStorage.cpp
index 3ede67e..b4abc27 100644
--- a/KeyStorage.cpp
+++ b/KeyStorage.cpp
@@ -117,9 +117,13 @@
     SHA512_Final(reinterpret_cast<uint8_t*>(&(*res)[0]), &c);
 }
 
-// Generates a keystore key, using rollback resistance if supported.
-static bool generateKeystoreKey(Keystore& keystore, const km::AuthorizationSetBuilder& paramBuilder,
-                                std::string* key) {
+static bool generateKeyStorageKey(Keystore& keystore, const std::string& appId, std::string* key) {
+    auto paramBuilder = km::AuthorizationSetBuilder()
+                                .AesEncryptionKey(AES_KEY_BYTES * 8)
+                                .GcmModeMinMacLen(GCM_MAC_BYTES * 8)
+                                .Authorization(km::TAG_APPLICATION_ID, appId)
+                                .Authorization(km::TAG_NO_AUTH_REQUIRED);
+    LOG(DEBUG) << "Generating \"key storage\" key";
     auto paramsWithRollback = paramBuilder;
     paramsWithRollback.Authorization(km::TAG_ROLLBACK_RESISTANCE);
 
@@ -132,23 +136,13 @@
     return true;
 }
 
-static bool generateKeyStorageKey(Keystore& keystore, const std::string& appId, std::string* key) {
-    auto paramBuilder = km::AuthorizationSetBuilder()
-                                .AesEncryptionKey(AES_KEY_BYTES * 8)
-                                .GcmModeMinMacLen(GCM_MAC_BYTES * 8)
-                                .Authorization(km::TAG_APPLICATION_ID, appId)
-                                .Authorization(km::TAG_NO_AUTH_REQUIRED);
-    LOG(DEBUG) << "Generating \"key storage\" key";
-    return generateKeystoreKey(keystore, paramBuilder, key);
-}
-
 bool generateWrappedStorageKey(KeyBuffer* key) {
     Keystore keystore;
     if (!keystore) return false;
     std::string key_temp;
     auto paramBuilder = km::AuthorizationSetBuilder().AesEncryptionKey(AES_KEY_BYTES * 8);
     paramBuilder.Authorization(km::TAG_STORAGE_KEY);
-    if (!generateKeystoreKey(keystore, paramBuilder, &key_temp)) return false;
+    if (!keystore.generateKey(paramBuilder, &key_temp)) return false;
     *key = KeyBuffer(key_temp.size());
     memcpy(reinterpret_cast<void*>(key->data()), key_temp.c_str(), key->size());
     return true;
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index 1284158..ea2c98c 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -495,12 +495,13 @@
 binder::Status VoldNativeService::setGCUrgentPace(int32_t neededSegments,
                                                   int32_t minSegmentThreshold,
                                                   float dirtyReclaimRate, float reclaimWeight,
-                                                  int32_t gcPeriod, int32_t minGCSleepTime) {
+                                                  int32_t gcPeriod, int32_t minGCSleepTime,
+                                                  int32_t targetDirtyRatio) {
     ENFORCE_SYSTEM_OR_ROOT;
     ACQUIRE_LOCK;
 
     SetGCUrgentPace(neededSegments, minSegmentThreshold, dirtyReclaimRate, reclaimWeight, gcPeriod,
-                    minGCSleepTime);
+                    minGCSleepTime, targetDirtyRatio);
     return Ok();
 }
 
diff --git a/VoldNativeService.h b/VoldNativeService.h
index 50ef4e3..37a988b 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -91,7 +91,7 @@
     binder::Status getStorageLifeTime(int32_t* _aidl_return);
     binder::Status setGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold,
                                    float dirtyReclaimRate, float reclaimWeight, int32_t gcPeriod,
-                                   int32_t minGCSleepTime);
+                                   int32_t minGCSleepTime, int32_t targetDirtyRatio);
     binder::Status refreshLatestWrite();
     binder::Status getWriteAmount(int32_t* _aidl_return);
 
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index 8422efb..77478d9 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -69,7 +69,8 @@
     int getStorageLifeTime();
     void setGCUrgentPace(int neededSegments, int minSegmentThreshold,
                          float dirtyReclaimRate, float reclaimWeight,
-                         int gcPeriod, int minGCSleepTime);
+                         int gcPeriod, int minGCSleepTime,
+                         int targetDirtyRatio);
     void refreshLatestWrite();
     int getWriteAmount();