Merge "Make UpdatableSystemFontTest device side test." into sc-dev am: 129c595177 am: 634d72c9ab
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14411838 Change-Id: I7e236435a71bdfe1d74eb4c5428284892aceeb96
This commit is contained in:
@@ -21,16 +21,15 @@ package {
|
|||||||
default_applicable_licenses: ["frameworks_base_license"],
|
default_applicable_licenses: ["frameworks_base_license"],
|
||||||
}
|
}
|
||||||
|
|
||||||
java_test_host {
|
android_test {
|
||||||
name: "UpdatableSystemFontTest",
|
name: "UpdatableSystemFontTest",
|
||||||
srcs: ["src/**/*.java"],
|
srcs: ["src/**/*.java"],
|
||||||
libs: [
|
libs: ["android.test.runner"],
|
||||||
"tradefed",
|
|
||||||
"compatibility-tradefed",
|
|
||||||
"compatibility-host-util",
|
|
||||||
],
|
|
||||||
static_libs: [
|
static_libs: [
|
||||||
"frameworks-base-hostutils",
|
"androidx.test.ext.junit",
|
||||||
|
"compatibility-device-util-axt",
|
||||||
|
"platform-test-annotations",
|
||||||
|
"truth-prebuilt",
|
||||||
],
|
],
|
||||||
test_suites: [
|
test_suites: [
|
||||||
"general-tests",
|
"general-tests",
|
||||||
@@ -47,4 +46,5 @@ java_test_host {
|
|||||||
":UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf",
|
":UpdatableSystemFontTestNotoColorEmojiVPlus2Ttf",
|
||||||
":UpdatableSystemFontTestNotoColorEmojiVPlus2TtfFsvSig",
|
":UpdatableSystemFontTestNotoColorEmojiVPlus2TtfFsvSig",
|
||||||
],
|
],
|
||||||
|
sdk_version: "test_current",
|
||||||
}
|
}
|
||||||
|
|||||||
30
tests/UpdatableSystemFontTest/AndroidManifest.xml
Normal file
30
tests/UpdatableSystemFontTest/AndroidManifest.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2021 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.android.updatablesystemfont">
|
||||||
|
|
||||||
|
<application android:label="UpdatableSystemFontTest">
|
||||||
|
<uses-library android:name="android.test.runner"/>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
android:label="UpdatableSystemFontTest"
|
||||||
|
android:targetPackage="com.android.updatablesystemfont">
|
||||||
|
</instrumentation>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||||
<option name="cleanup-apks" value="true" />
|
<option name="cleanup-apks" value="true" />
|
||||||
|
<option name="test-file-name" value="UpdatableSystemFontTest.apk" />
|
||||||
<option name="test-file-name" value="EmojiRenderingTestApp.apk" />
|
<option name="test-file-name" value="EmojiRenderingTestApp.apk" />
|
||||||
</target_preparer>
|
</target_preparer>
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@
|
|||||||
<option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig" />
|
<option name="push" value="UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiVPlus2.ttf.fsv_sig" />
|
||||||
</target_preparer>
|
</target_preparer>
|
||||||
|
|
||||||
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
|
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
|
||||||
<option name="jar" value="UpdatableSystemFontTest.jar" />
|
<option name="package" value="com.android.updatablesystemfont" />
|
||||||
</test>
|
</test>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@@ -17,26 +17,35 @@
|
|||||||
package com.android.updatablesystemfont;
|
package com.android.updatablesystemfont;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.common.truth.Truth.assertWithMessage;
|
|
||||||
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
|
||||||
|
import android.app.UiAutomation;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.platform.test.annotations.RootPermissionTest;
|
import android.platform.test.annotations.RootPermissionTest;
|
||||||
|
import android.security.FileIntegrityManager;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.android.fsverity.AddFsVerityCertRule;
|
import androidx.annotation.Nullable;
|
||||||
import com.android.tradefed.device.DeviceNotAvailableException;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.android.tradefed.log.LogUtil.CLog;
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
|
|
||||||
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
|
import com.android.compatibility.common.util.StreamUtil;
|
||||||
import com.android.tradefed.util.CommandResult;
|
|
||||||
import com.android.tradefed.util.CommandStatus;
|
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -44,9 +53,10 @@ import java.util.regex.Pattern;
|
|||||||
* Tests if fonts can be updated by 'cmd font'.
|
* Tests if fonts can be updated by 'cmd font'.
|
||||||
*/
|
*/
|
||||||
@RootPermissionTest
|
@RootPermissionTest
|
||||||
@RunWith(DeviceJUnit4ClassRunner.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
|
public class UpdatableSystemFontTest {
|
||||||
|
|
||||||
|
private static final String TAG = "UpdatableSystemFontTest";
|
||||||
private static final String SYSTEM_FONTS_DIR = "/system/fonts/";
|
private static final String SYSTEM_FONTS_DIR = "/system/fonts/";
|
||||||
private static final String DATA_FONTS_DIR = "/data/fonts/files/";
|
private static final String DATA_FONTS_DIR = "/data/fonts/files/";
|
||||||
|
|
||||||
@@ -84,58 +94,65 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
|
|||||||
T get() throws Exception;
|
T get() throws Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Rule
|
private String mKeyId;
|
||||||
public final AddFsVerityCertRule mAddFsverityCertRule =
|
|
||||||
new AddFsVerityCertRule(this, CERT_PATH);
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
expectRemoteCommandToSucceed("cmd font clear");
|
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||||
|
// Run tests only if updatable system font is enabled.
|
||||||
|
FileIntegrityManager fim = context.getSystemService(FileIntegrityManager.class);
|
||||||
|
assumeTrue(fim != null);
|
||||||
|
assumeTrue(fim.isApkVeritySupported());
|
||||||
|
mKeyId = insertCert(CERT_PATH);
|
||||||
|
expectCommandToSucceed("cmd font clear");
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
expectRemoteCommandToSucceed("cmd font clear");
|
expectCommandToSucceed("cmd font clear");
|
||||||
|
if (mKeyId != null) {
|
||||||
|
expectCommandToSucceed("mini-keyctl unlink " + mKeyId + " .fs-verity");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateFont() throws Exception {
|
public void updateFont() throws Exception {
|
||||||
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
|
expectCommandToSucceed(String.format("cmd font update %s %s",
|
||||||
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
||||||
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
||||||
assertThat(fontPath).startsWith(DATA_FONTS_DIR);
|
assertThat(fontPath).startsWith(DATA_FONTS_DIR);
|
||||||
// The updated font should be readable and unmodifiable.
|
// The updated font should be readable and unmodifiable.
|
||||||
expectRemoteCommandToSucceed("cat " + fontPath + " > /dev/null");
|
expectCommandToSucceed("dd status=none if=" + fontPath + " of=/dev/null");
|
||||||
expectRemoteCommandToFail("echo -n '' >> " + fontPath);
|
expectCommandToFail("dd status=none if=" + CERT_PATH + " of=" + fontPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateFont_twice() throws Exception {
|
public void updateFont_twice() throws Exception {
|
||||||
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
|
expectCommandToSucceed(String.format("cmd font update %s %s",
|
||||||
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
||||||
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
||||||
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
|
expectCommandToSucceed(String.format("cmd font update %s %s",
|
||||||
TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG));
|
TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG));
|
||||||
String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
||||||
assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
|
assertThat(fontPath2).startsWith(DATA_FONTS_DIR);
|
||||||
assertThat(fontPath2).isNotEqualTo(fontPath);
|
assertThat(fontPath2).isNotEqualTo(fontPath);
|
||||||
// The new file should be readable.
|
// The new file should be readable.
|
||||||
expectRemoteCommandToSucceed("cat " + fontPath2 + " > /dev/null");
|
expectCommandToSucceed("dd status=none if=" + fontPath2 + " of=/dev/null");
|
||||||
// The old file should be still readable.
|
// The old file should be still readable.
|
||||||
expectRemoteCommandToSucceed("cat " + fontPath + " > /dev/null");
|
expectCommandToSucceed("dd status=none if=" + fontPath + " of=/dev/null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateFont_allowSameVersion() throws Exception {
|
public void updateFont_allowSameVersion() throws Exception {
|
||||||
// Update original font to the same version
|
// Update original font to the same version
|
||||||
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
|
expectCommandToSucceed(String.format("cmd font update %s %s",
|
||||||
ORIGINAL_NOTO_COLOR_EMOJI_TTF, ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG));
|
ORIGINAL_NOTO_COLOR_EMOJI_TTF, ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG));
|
||||||
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
||||||
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
|
expectCommandToSucceed(String.format("cmd font update %s %s",
|
||||||
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
||||||
String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
||||||
// Update updated font to the same version
|
// Update updated font to the same version
|
||||||
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
|
expectCommandToSucceed(String.format("cmd font update %s %s",
|
||||||
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
||||||
String fontPath3 = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
String fontPath3 = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
||||||
assertThat(fontPath).startsWith(DATA_FONTS_DIR);
|
assertThat(fontPath).startsWith(DATA_FONTS_DIR);
|
||||||
@@ -147,21 +164,21 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateFont_invalidCert() throws Exception {
|
public void updateFont_invalidCert() throws Exception {
|
||||||
expectRemoteCommandToFail(String.format("cmd font update %s %s",
|
expectCommandToFail(String.format("cmd font update %s %s",
|
||||||
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG));
|
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateFont_downgradeFromSystem() throws Exception {
|
public void updateFont_downgradeFromSystem() throws Exception {
|
||||||
expectRemoteCommandToFail(String.format("cmd font update %s %s",
|
expectCommandToFail(String.format("cmd font update %s %s",
|
||||||
TEST_NOTO_COLOR_EMOJI_V0_TTF, TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG));
|
TEST_NOTO_COLOR_EMOJI_V0_TTF, TEST_NOTO_COLOR_EMOJI_V0_TTF_FSV_SIG));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateFont_downgradeFromData() throws Exception {
|
public void updateFont_downgradeFromData() throws Exception {
|
||||||
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
|
expectCommandToSucceed(String.format("cmd font update %s %s",
|
||||||
TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG));
|
TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS2_TTF_FSV_SIG));
|
||||||
expectRemoteCommandToFail(String.format("cmd font update %s %s",
|
expectCommandToFail(String.format("cmd font update %s %s",
|
||||||
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +195,7 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
|
|||||||
public void launchApp_afterUpdateFont() throws Exception {
|
public void launchApp_afterUpdateFont() throws Exception {
|
||||||
String originalFontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
String originalFontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
||||||
assertThat(originalFontPath).startsWith(SYSTEM_FONTS_DIR);
|
assertThat(originalFontPath).startsWith(SYSTEM_FONTS_DIR);
|
||||||
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
|
expectCommandToSucceed(String.format("cmd font update %s %s",
|
||||||
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
||||||
String updatedFontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
String updatedFontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
||||||
assertThat(updatedFontPath).startsWith(DATA_FONTS_DIR);
|
assertThat(updatedFontPath).startsWith(DATA_FONTS_DIR);
|
||||||
@@ -191,57 +208,99 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void reboot() throws Exception {
|
public void reboot() throws Exception {
|
||||||
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
|
expectCommandToSucceed(String.format("cmd font update %s %s",
|
||||||
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG));
|
||||||
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
||||||
assertThat(fontPath).startsWith(DATA_FONTS_DIR);
|
assertThat(fontPath).startsWith(DATA_FONTS_DIR);
|
||||||
|
|
||||||
// Emulate reboot by 'cmd font restart'.
|
// Emulate reboot by 'cmd font restart'.
|
||||||
expectRemoteCommandToSucceed("cmd font restart");
|
expectCommandToSucceed("cmd font restart");
|
||||||
String fontPathAfterReboot = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
String fontPathAfterReboot = getFontPath(NOTO_COLOR_EMOJI_TTF);
|
||||||
assertThat(fontPathAfterReboot).isEqualTo(fontPath);
|
assertThat(fontPathAfterReboot).isEqualTo(fontPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getFontPath(String fontFileName) throws Exception {
|
private static String insertCert(String certPath) throws Exception {
|
||||||
|
Pair<String, String> result;
|
||||||
|
try (InputStream is = new FileInputStream(certPath)) {
|
||||||
|
result = runShellCommand("mini-keyctl padd asymmetric fsv_test .fs-verity", is);
|
||||||
|
}
|
||||||
|
// Assert that there are no errors.
|
||||||
|
assertThat(result.second).isEmpty();
|
||||||
|
String keyId = result.first.trim();
|
||||||
|
assertThat(keyId).matches("^\\d+$");
|
||||||
|
return keyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getFontPath(String fontFileName) throws Exception {
|
||||||
// TODO: add a dedicated command for testing.
|
// TODO: add a dedicated command for testing.
|
||||||
String lines = expectRemoteCommandToSucceed("cmd font dump");
|
String lines = expectCommandToSucceed("cmd font dump");
|
||||||
for (String line : lines.split("\n")) {
|
for (String line : lines.split("\n")) {
|
||||||
Matcher m = PATTERN_FONT.matcher(line);
|
Matcher m = PATTERN_FONT.matcher(line);
|
||||||
if (m.find() && m.group(1).endsWith(fontFileName)) {
|
if (m.find() && m.group(1).endsWith(fontFileName)) {
|
||||||
return m.group(1);
|
return m.group(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CLog.e("Font not found: " + fontFileName);
|
throw new AssertionError("Font not found: " + fontFileName);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startActivity(String appId, String activityId) throws Exception {
|
private static void startActivity(String appId, String activityId) throws Exception {
|
||||||
// Make sure that the app is installed and enabled.
|
// Make sure that the app is installed and enabled.
|
||||||
waitUntil(ACTIVITY_TIMEOUT_MILLIS, () -> {
|
waitUntil(ACTIVITY_TIMEOUT_MILLIS, () -> {
|
||||||
String packageInfo = expectRemoteCommandToSucceed(
|
String packageInfo = expectCommandToSucceed("pm list packages -e " + appId);
|
||||||
"pm list packages -e " + EMOJI_RENDERING_TEST_APP_ID);
|
|
||||||
return !packageInfo.isEmpty();
|
return !packageInfo.isEmpty();
|
||||||
});
|
});
|
||||||
expectRemoteCommandToSucceed("am force-stop " + EMOJI_RENDERING_TEST_APP_ID);
|
expectCommandToSucceed("am force-stop " + appId);
|
||||||
expectRemoteCommandToSucceed("am start-activity -n " + EMOJI_RENDERING_TEST_ACTIVITY);
|
expectCommandToSucceed("am start-activity -n " + activityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String expectRemoteCommandToSucceed(String cmd) throws Exception {
|
private static String expectCommandToSucceed(String cmd) throws IOException {
|
||||||
CommandResult result = getDevice().executeShellV2Command(cmd);
|
Pair<String, String> result = runShellCommand(cmd, null);
|
||||||
assertWithMessage("`" + cmd + "` failed: " + result.getStderr())
|
// UiAutomation.runShellCommand() does not return exit code.
|
||||||
.that(result.getStatus())
|
// Assume that the command fails if stderr is not empty.
|
||||||
.isEqualTo(CommandStatus.SUCCESS);
|
assertThat(result.second.trim()).isEmpty();
|
||||||
return result.getStdout();
|
return result.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expectRemoteCommandToFail(String cmd) throws Exception {
|
private static void expectCommandToFail(String cmd) throws IOException {
|
||||||
CommandResult result = getDevice().executeShellV2Command(cmd);
|
Pair<String, String> result = runShellCommand(cmd, null);
|
||||||
assertWithMessage("Unexpected success from `" + cmd + "`: " + result.getStderr())
|
// UiAutomation.runShellCommand() does not return exit code.
|
||||||
.that(result.getStatus())
|
// Assume that the command fails if stderr is not empty.
|
||||||
.isNotEqualTo(CommandStatus.SUCCESS);
|
assertThat(result.second.trim()).isNotEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitUntil(long timeoutMillis, ThrowingSupplier<Boolean> func) {
|
/** Runs a command and returns (stdout, stderr). */
|
||||||
|
private static Pair<String, String> runShellCommand(String cmd, @Nullable InputStream input)
|
||||||
|
throws IOException {
|
||||||
|
Log.i(TAG, "runShellCommand: " + cmd);
|
||||||
|
UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
|
||||||
|
ParcelFileDescriptor[] rwe = automation.executeShellCommandRwe(cmd);
|
||||||
|
// executeShellCommandRwe returns [stdout, stdin, stderr].
|
||||||
|
try (ParcelFileDescriptor outFd = rwe[0];
|
||||||
|
ParcelFileDescriptor inFd = rwe[1];
|
||||||
|
ParcelFileDescriptor errFd = rwe[2]) {
|
||||||
|
if (input != null) {
|
||||||
|
try (OutputStream os = new FileOutputStream(inFd.getFileDescriptor())) {
|
||||||
|
StreamUtil.copyStreams(input, os);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We have to close stdin before reading stdout and stderr.
|
||||||
|
// It's safe to close ParcelFileDescriptor multiple times.
|
||||||
|
inFd.close();
|
||||||
|
String stdout;
|
||||||
|
try (InputStream is = new FileInputStream(outFd.getFileDescriptor())) {
|
||||||
|
stdout = StreamUtil.readInputStream(is);
|
||||||
|
}
|
||||||
|
Log.i(TAG, "stdout = " + stdout);
|
||||||
|
String stderr;
|
||||||
|
try (InputStream is = new FileInputStream(errFd.getFileDescriptor())) {
|
||||||
|
stderr = StreamUtil.readInputStream(is);
|
||||||
|
}
|
||||||
|
Log.i(TAG, "stderr = " + stderr);
|
||||||
|
return new Pair<>(stdout, stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void waitUntil(long timeoutMillis, ThrowingSupplier<Boolean> func) {
|
||||||
long untilMillis = System.currentTimeMillis() + timeoutMillis;
|
long untilMillis = System.currentTimeMillis() + timeoutMillis;
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
@@ -256,25 +315,16 @@ public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
|
|||||||
throw new AssertionError("Timed out");
|
throw new AssertionError("Timed out");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isFileOpenedBy(String path, String appId) throws DeviceNotAvailableException {
|
private static boolean isFileOpenedBy(String path, String appId) throws Exception {
|
||||||
String pid = pidOf(appId);
|
String pid = pidOf(appId);
|
||||||
if (pid.isEmpty()) {
|
if (pid.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CommandResult result = getDevice().executeShellV2Command(
|
String cmd = String.format("lsof -t -p %s %s", pid, path);
|
||||||
String.format("lsof -t -p %s '%s'", pid, path));
|
return !expectCommandToSucceed(cmd).trim().isEmpty();
|
||||||
if (result.getStatus() != CommandStatus.SUCCESS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// The file is open if the output of lsof is non-empty.
|
|
||||||
return !result.getStdout().trim().isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String pidOf(String appId) throws DeviceNotAvailableException {
|
private static String pidOf(String appId) throws Exception {
|
||||||
CommandResult result = getDevice().executeShellV2Command("pidof " + appId);
|
return expectCommandToSucceed("pidof " + appId).trim();
|
||||||
if (result.getStatus() != CommandStatus.SUCCESS) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return result.getStdout().trim();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user