diff options
| author | 2022-09-27 20:55:42 +0000 | |
|---|---|---|
| committer | 2022-09-27 20:55:42 +0000 | |
| commit | c12a383385d4b96190d290546c03e3bf80865938 (patch) | |
| tree | 5f18f9946e9e2839738f1c2beafe66aa37da24ef | |
| parent | 2e77ad99c6d5403f8fae037b70e78b5281cfc46c (diff) | |
| parent | 7afbbec42f4d30be77a818552aa2201e54c8b798 (diff) | |
Merge changes from topic "ddr_size_api"
* changes:
Add new field in MemoryInfo to get advertised memory size.
Add method to parse the size in FileUtils
| -rw-r--r-- | core/api/current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/app/ActivityManager.java | 12 | ||||
| -rw-r--r-- | core/java/android/os/FileUtils.java | 81 | ||||
| -rw-r--r-- | core/java/android/os/Process.java | 19 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/os/FileUtilsTest.java | 54 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/os/ProcessTest.java | 3 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ProcessList.java | 2 |
7 files changed, 170 insertions, 2 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 644a194f6ed1..05e2a9aa7286 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -4415,6 +4415,7 @@ package android.app { method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.ActivityManager.MemoryInfo> CREATOR; + field public long advertisedMem; field public long availMem; field public boolean lowMemory; field public long threshold; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 5d1d225f4d2d..6f9a98d8313f 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -29,6 +29,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -2813,6 +2814,15 @@ public class ActivityManager { */ public static class MemoryInfo implements Parcelable { /** + * The advertised memory of the system, as the end user would encounter in a retail display + * environment. This value might be different from {@code totalMem}. This could be due to + * many reasons. For example, the ODM could reserve part of the memory for the Trusted + * Execution Environment (TEE) which the kernel doesn't have access or knowledge about it. + */ + @SuppressLint("MutableBareField") + public long advertisedMem; + + /** * The available memory on the system. This number should not * be considered absolute: due to the nature of the kernel, a significant * portion of this memory is actually in use and needed for the overall @@ -2861,6 +2871,7 @@ public class ActivityManager { } public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(advertisedMem); dest.writeLong(availMem); dest.writeLong(totalMem); dest.writeLong(threshold); @@ -2872,6 +2883,7 @@ public class ActivityManager { } public void readFromParcel(Parcel source) { + advertisedMem = source.readLong(); availMem = source.readLong(); totalMem = source.readLong(); threshold = source.readLong(); diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index edfcb3d6f12a..d5c3de146015 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -54,6 +54,7 @@ import android.system.ErrnoException; import android.system.Os; import android.system.StructStat; import android.text.TextUtils; +import android.util.DataUnit; import android.util.Log; import android.util.Slog; import android.webkit.MimeTypeMap; @@ -83,6 +84,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; +import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -1309,6 +1311,85 @@ public final class FileUtils { return val * pow; } + private static long toBytes(long value, String unit) { + unit = unit.toUpperCase(); + + if (List.of("B").contains(unit)) { + return value; + } + + if (List.of("K", "KB").contains(unit)) { + return DataUnit.KILOBYTES.toBytes(value); + } + + if (List.of("M", "MB").contains(unit)) { + return DataUnit.MEGABYTES.toBytes(value); + } + + if (List.of("G", "GB").contains(unit)) { + return DataUnit.GIGABYTES.toBytes(value); + } + + if (List.of("KI", "KIB").contains(unit)) { + return DataUnit.KIBIBYTES.toBytes(value); + } + + if (List.of("MI", "MIB").contains(unit)) { + return DataUnit.MEBIBYTES.toBytes(value); + } + + if (List.of("GI", "GIB").contains(unit)) { + return DataUnit.GIBIBYTES.toBytes(value); + } + + return Long.MIN_VALUE; + } + + /** + * @param fmtSize The string that contains the size to be parsed. The + * expected format is: + * + * <p>"^((\\s*[-+]?[0-9]+)\\s*(B|K|KB|M|MB|G|GB|Ki|KiB|Mi|MiB|Gi|GiB)\\s*)$" + * + * <p>For example: 10Kb, 500GiB, 100mb. The unit is not case sensitive. + * + * @return the size in bytes. If {@code fmtSize} has invalid format, it + * returns {@link Long#MIN_VALUE}. + * @hide + */ + public static long parseSize(@Nullable String fmtSize) { + if (fmtSize == null || fmtSize.isBlank()) { + return Long.MIN_VALUE; + } + + int sign = 1; + fmtSize = fmtSize.trim(); + char first = fmtSize.charAt(0); + if (first == '-' || first == '+') { + if (first == '-') { + sign = -1; + } + + fmtSize = fmtSize.replace(first + "", ""); + } + + int index = 0; + // Find the last index of the value in fmtSize. + while (index < fmtSize.length() && Character.isDigit(fmtSize.charAt(index))) { + index++; + } + + // Check if number and units are present. + if (index == 0 || index == fmtSize.length()) { + return Long.MIN_VALUE; + } + + long value = sign * Long.valueOf(fmtSize.substring(0, index)); + String unit = fmtSize.substring(index).trim(); + + return toBytes(value, unit); + } + /** * Closes the given object quietly, ignoring any checked exceptions. Does * nothing if the given object is {@code null}. diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index e06e7326a860..b3afaecca849 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -26,6 +26,7 @@ import android.annotation.TestApi; import android.annotation.UptimeMillisLong; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build.VERSION_CODES; +import android.sysprop.MemoryProperties; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; @@ -1336,6 +1337,24 @@ public class Process { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public static final native void sendSignalQuiet(int pid, int signal); + /** + * @return The advertised memory of the system, as the end user would encounter in a retail + * display environment. If the advertised memory is not defined, it returns + * {@code getTotalMemory()} rounded. + * + * @hide + */ + public static final long getAdvertisedMem() { + String formatSize = MemoryProperties.memory_ddr_size().orElse("0KB"); + long memSize = FileUtils.parseSize(formatSize); + + if (memSize == Long.MIN_VALUE) { + return FileUtils.roundStorageSize(getTotalMemory()); + } + + return memSize; + } + /** @hide */ @UnsupportedAppUsage public static final native long getFreeMemory(); diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java index c1e72fe75666..5f731e201866 100644 --- a/core/tests/coretests/src/android/os/FileUtilsTest.java +++ b/core/tests/coretests/src/android/os/FileUtilsTest.java @@ -58,10 +58,10 @@ import android.provider.DocumentsContract.Document; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; -import libcore.io.Streams; - import com.google.android.collect.Sets; +import libcore.io.Streams; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -524,6 +524,56 @@ public class FileUtilsTest { } @Test + public void testParseSize() { + assertEquals(0L, FileUtils.parseSize("0MB")); + assertEquals(1_024L, FileUtils.parseSize("1024b")); + assertEquals(-1L, FileUtils.parseSize(" -1 b ")); + assertEquals(0L, FileUtils.parseSize(" -0 gib ")); + assertEquals(1_000L, FileUtils.parseSize("1K")); + assertEquals(1_000L, FileUtils.parseSize("1KB")); + assertEquals(10_000L, FileUtils.parseSize("10KB")); + assertEquals(100_000L, FileUtils.parseSize("100KB")); + assertEquals(1_000_000L, FileUtils.parseSize("1000KB")); + assertEquals(1_024_000L, FileUtils.parseSize("1000KiB")); + assertEquals(70_000_000L, FileUtils.parseSize("070M")); + assertEquals(70_000_000L, FileUtils.parseSize("070MB")); + assertEquals(73_400_320L, FileUtils.parseSize("70MiB")); + assertEquals(700_000_000L, FileUtils.parseSize("700000KB")); + assertEquals(200_000_000L, FileUtils.parseSize("+200MB")); + assertEquals(1_000_000_000L, FileUtils.parseSize("1000MB")); + assertEquals(1_000_000_000L, FileUtils.parseSize("+1000 mb")); + assertEquals(644_245_094_400L, FileUtils.parseSize("600GiB")); + assertEquals(999_000_000_000L, FileUtils.parseSize("999GB")); + assertEquals(999_000_000_000L, FileUtils.parseSize("999 gB")); + assertEquals(9_999_000_000_000L, FileUtils.parseSize("9999GB")); + assertEquals(9_000_000_000_000L, FileUtils.parseSize(" 9000 GB ")); + assertEquals(1_234_000_000_000L, FileUtils.parseSize(" 1234 GB ")); + assertEquals(1_234_567_890_000L, FileUtils.parseSize(" 1234567890 KB ")); + } + + @Test + public void testParseSize_invalidArguments() { + assertEquals(Long.MIN_VALUE, FileUtils.parseSize(null)); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("null")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize(" ")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("KB")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("123 dd")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("Invalid")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize(" ABC890 KB ")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("-=+90 KB ")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("123")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("--123")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("-KB")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("++123")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("+")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("+ 1 +")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("+--+ 1 +")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("1GB+")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize(" + 1234567890 KB ")); + } + + @Test public void testTranslateMode() throws Exception { assertTranslate("r", O_RDONLY, MODE_READ_ONLY); diff --git a/core/tests/coretests/src/android/os/ProcessTest.java b/core/tests/coretests/src/android/os/ProcessTest.java index ae4edb97aab0..52846dfbb14b 100644 --- a/core/tests/coretests/src/android/os/ProcessTest.java +++ b/core/tests/coretests/src/android/os/ProcessTest.java @@ -72,4 +72,7 @@ public class ProcessTest extends TestCase { assertEquals(-1, Process.getThreadGroupLeader(BAD_PID)); } + public void testGetAdvertisedMem() { + assertTrue(Process.getTotalMemory() <= Process.getAdvertisedMem()); + } } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 178b6bbe755e..eb6a3b3a3cea 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -27,6 +27,7 @@ import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import static android.os.Process.SYSTEM_UID; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; +import static android.os.Process.getAdvertisedMem; import static android.os.Process.getFreeMemory; import static android.os.Process.getTotalMemory; import static android.os.Process.killProcessQuiet; @@ -1524,6 +1525,7 @@ public final class ProcessList { void getMemoryInfo(ActivityManager.MemoryInfo outInfo) { final long homeAppMem = getMemLevel(HOME_APP_ADJ); final long cachedAppMem = getMemLevel(CACHED_APP_MIN_ADJ); + outInfo.advertisedMem = getAdvertisedMem(); outInfo.availMem = getFreeMemory(); outInfo.totalMem = getTotalMemory(); outInfo.threshold = homeAppMem; |