/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.compatibility.common.util; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.ActivityManager; import android.app.ActivityManager.MemoryInfo; import android.app.Instrumentation; import android.app.UiAutomation; import android.content.Context; import android.os.ParcelFileDescriptor; import android.os.StatFs; import android.util.Log; import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import com.android.modules.utils.build.SdkLevel; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.util.concurrent.Callable; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; public class SystemUtil { private static final String TAG = "CtsSystemUtil"; private static final long TIMEOUT_MILLIS = 10000; public static long getFreeDiskSize(Context context) { final StatFs statFs = new StatFs(context.getFilesDir().getAbsolutePath()); return (long)statFs.getAvailableBlocks() * statFs.getBlockSize(); } public static long getFreeMemory(Context context) { final MemoryInfo info = new MemoryInfo(); ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(info); return info.availMem; } public static long getTotalMemory(Context context) { final MemoryInfo info = new MemoryInfo(); ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(info); return info.totalMem; } /** * Executes a shell command using shell user identity, and return the standard output in string *
Note: calling this function requires API level 21 or above * @param instrumentation {@link Instrumentation} instance, obtained from a test running in * instrumentation framework * @param cmd the command to run * @return the standard output of the command * @throws Exception */ public static String runShellCommand(Instrumentation instrumentation, String cmd) throws IOException { return runShellCommand(instrumentation.getUiAutomation(), cmd); } /** * Executes a shell command using shell user identity, and return the standard output in string *
Note: calling this function requires API level 21 or above * @param automation {@link UiAutomation} instance, obtained from a test running in * instrumentation framework * @param cmd the command to run * @return the standard output of the command * @throws Exception */ public static String runShellCommand(UiAutomation automation, String cmd) throws IOException { return new String(runShellCommandByteOutput(automation, cmd)); } /** * Executes a shell command using shell user identity, and return the standard output as a byte * array *
Note: calling this function requires API level 21 or above
*
* @param automation {@link UiAutomation} instance, obtained from a test running in
* instrumentation framework
* @param cmd the command to run
* @return the standard output of the command as a byte array
*/
static byte[] runShellCommandByteOutput(UiAutomation automation, String cmd)
throws IOException {
checkCommandBeforeRunning(cmd);
ParcelFileDescriptor pfd = automation.executeShellCommand(cmd);
try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
return FileUtils.readInputStreamFully(fis);
}
}
private static void checkCommandBeforeRunning(String cmd) {
Log.v(TAG, "Running command: " + cmd);
if (cmd.startsWith("pm grant ") || cmd.startsWith("pm revoke ")) {
throw new UnsupportedOperationException("Use UiAutomation.grantRuntimePermission() "
+ "or revokeRuntimePermission() directly, which are more robust.");
}
}
/**
* Simpler version of {@link #runShellCommand(Instrumentation, String)}.
*/
public static String runShellCommand(String cmd) {
try {
return runShellCommand(InstrumentationRegistry.getInstrumentation(), cmd);
} catch (IOException e) {
fail("Failed reading command output: " + e);
return "";
}
}
/**
* Like {@link #runShellCommand(String)} but throws if anything was printed to stderr on S+, and
* delegates to {@link #runShellCommand(String)} on older platforms for compatibility.
*/
public static String runShellCommandOrThrow(String cmd) {
if (!SdkLevel.isAtLeastS()) {
return runShellCommand(cmd);
}
UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
try {
checkCommandBeforeRunning(cmd);
ParcelFileDescriptor[] fds = automation.executeShellCommandRwe(cmd);
ParcelFileDescriptor fdOut = fds[0];
ParcelFileDescriptor fdIn = fds[1];
ParcelFileDescriptor fdErr = fds[2];
if (fdIn != null) {
try {
// not using stdin
fdIn.close();
} catch (Exception e) {
// Ignore
}
}
String out;
String err;
try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(fdOut)) {
out = new String(FileUtils.readInputStreamFully(fis));
}
try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(fdErr)) {
err = new String(FileUtils.readInputStreamFully(fis));
}
if (!err.isEmpty()) {
fail("Command failed:\n$ " + cmd +
"\n\nstderr:\n" + err +
"\n\nstdout:\n" + out);
}
return out;
} catch (IOException e) {
fail("Failed reading command output: " + e);
return "";
}
}
/**
* Same as {@link #runShellCommand(String)}, with optionally
* check the result using {@code resultChecker}.
*/
public static String runShellCommand(String cmd, Predicate