summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Juan Yescas <jyescas@google.com> 2022-09-27 20:55:42 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2022-09-27 20:55:42 +0000
commitc12a383385d4b96190d290546c03e3bf80865938 (patch)
tree5f18f9946e9e2839738f1c2beafe66aa37da24ef
parent2e77ad99c6d5403f8fae037b70e78b5281cfc46c (diff)
parent7afbbec42f4d30be77a818552aa2201e54c8b798 (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.txt1
-rw-r--r--core/java/android/app/ActivityManager.java12
-rw-r--r--core/java/android/os/FileUtils.java81
-rw-r--r--core/java/android/os/Process.java19
-rw-r--r--core/tests/coretests/src/android/os/FileUtilsTest.java54
-rw-r--r--core/tests/coretests/src/android/os/ProcessTest.java3
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java2
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;