Get total physical memory size for ag/4495245.

Bug: 111134114
Change-Id: I2782a78e1ac41091d9d95c9d1e3f9254c1f7be7c
Fix: 111134114
Fixes: 111134114
Test: gts-tradefed run gts-dev --module GtsPlacementTestCases
Merged-In: I2782a78e1ac41091d9d95c9d1e3f9254c1f7be7c
diff --git a/src/com/android/tradefed/device/INativeDevice.java b/src/com/android/tradefed/device/INativeDevice.java
index 0cd4963..ff4071b 100644
--- a/src/com/android/tradefed/device/INativeDevice.java
+++ b/src/com/android/tradefed/device/INativeDevice.java
@@ -1188,4 +1188,7 @@
      * @param args the args to be replaced via String.format().
      */
     public void logOnDevice(String tag, LogLevel level, String format, Object... args);
+
+    /** Returns total physical memory size in bytes or -1 in case of internal error */
+    public long getTotalMemory();
 }
diff --git a/src/com/android/tradefed/device/NativeDevice.java b/src/com/android/tradefed/device/NativeDevice.java
index e31a9c1..2a20d12 100644
--- a/src/com/android/tradefed/device/NativeDevice.java
+++ b/src/com/android/tradefed/device/NativeDevice.java
@@ -4022,6 +4022,31 @@
         }
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public long getTotalMemory() {
+        // "/proc/meminfo" always returns value in kilobytes.
+        long totalMemory = 0;
+        String output = null;
+        try {
+            output = executeShellCommand("cat /proc/meminfo | grep MemTotal");
+        } catch (DeviceNotAvailableException e) {
+            CLog.e(e);
+            return -1;
+        }
+        if (output.isEmpty()) {
+            return -1;
+        }
+        String[] results = output.split("\\s+");
+        try {
+            totalMemory = Long.parseLong(results[1].replaceAll("\\D+", ""));
+        } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
+            CLog.e(e);
+            return -1;
+        }
+        return totalMemory * 1024;
+    }
+
     /** Validate that pid is an integer and not empty. */
     private boolean checkValidPid(String output) {
         if (output.isEmpty()) {
diff --git a/tests/src/com/android/tradefed/device/NativeDeviceTest.java b/tests/src/com/android/tradefed/device/NativeDeviceTest.java
index 633b3ae..d9329fa 100644
--- a/tests/src/com/android/tradefed/device/NativeDeviceTest.java
+++ b/tests/src/com/android/tradefed/device/NativeDeviceTest.java
@@ -2210,6 +2210,62 @@
         EasyMock.verify(mMockIDevice, mMockStateMonitor, mMockDvcMonitor);
     }
 
+    /** Test if valid shell output returns correct memory size. */
+    public void testGetTotalMemory() {
+        final long expectSize = 1902936064;
+        mTestDevice =
+                new TestableAndroidNativeDevice() {
+                    @Override
+                    public String executeShellCommand(String command)
+                            throws DeviceNotAvailableException {
+                        return "MemTotal:        1858336 kB";
+                    }
+                };
+        assertEquals(expectSize, mTestDevice.getTotalMemory());
+    }
+
+    /** Test if empty shell output returns -1. */
+    public void testGetTotalMemory_emptyString() {
+        final long expectSize = -1;
+        mTestDevice =
+                new TestableAndroidNativeDevice() {
+                    @Override
+                    public String executeShellCommand(String command)
+                            throws DeviceNotAvailableException {
+                        return "";
+                    }
+                };
+        assertEquals(expectSize, mTestDevice.getTotalMemory());
+    }
+
+    /** Test if unexpected shell output returns -1. */
+    public void testGetTotalMemory_unexpectedFormat() {
+        final long expectSize = -1;
+        mTestDevice =
+                new TestableAndroidNativeDevice() {
+                    @Override
+                    public String executeShellCommand(String command)
+                            throws DeviceNotAvailableException {
+                        return "1858336 kB";
+                    }
+                };
+        assertEquals(expectSize, mTestDevice.getTotalMemory());
+    }
+
+    /** Test if catching exception returns -1. */
+    public void testGetTotalMemory_exception() {
+        final long expectSize = -1;
+        mTestDevice =
+                new TestableAndroidNativeDevice() {
+                    @Override
+                    public String executeShellCommand(String command)
+                            throws DeviceNotAvailableException {
+                        throw new DeviceNotAvailableException();
+                    }
+                };
+        assertEquals(expectSize, mTestDevice.getTotalMemory());
+    }
+
     /**
      * Test that when a {@link NativeDevice#getLogcatSince(long)} is requested a matching logcat
      * command is generated.