Integration test for updatable system font.

This test:
(1) signs a font file with the test key.
(2) side-loads the test cert to the device under test.
(3) verifies that the signed font file can be installed.

The device must be rootable for doing step (2).

Bug: 176939176
Test: atest UpdatableSystemFontTest
Change-Id: I7a9b614aa3c77589c3495b663cb76056ba657006
This commit is contained in:
Kohsuke Yatoh 2021-01-31 23:48:46 -08:00
parent ad68508496
commit bc7182206b
13 changed files with 511 additions and 21 deletions

View File

@ -1294,6 +1294,18 @@ python_binary_host {
],
}
python_binary_host {
name: "update_font_metadata",
defaults: ["base_default"],
main: "tools/fonts/update_font_metadata.py",
srcs: [
"tools/fonts/update_font_metadata.py",
],
libs: [
"fontTools",
],
}
filegroup {
name: "framework-media-annotation-srcs",
srcs: [

View File

@ -169,8 +169,9 @@ public class FontManagerShellCommand extends ShellCommand {
sb.append(c++);
sb.append("]: lang=\"");
sb.append(family.getLocaleList().toLanguageTags());
sb.append("\"");
if (family.getVariant() != FontConfig.FontFamily.VARIANT_DEFAULT) {
sb.append("\", variant=");
sb.append(", variant=");
switch (family.getVariant()) {
case FontConfig.FontFamily.VARIANT_COMPACT:
sb.append("Compact");

View File

@ -16,6 +16,7 @@ java_test_host {
name: "ApkVerityTest",
srcs: ["src/**/*.java"],
libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"],
static_libs: ["frameworks-base-hostutils"],
test_suites: ["general-tests", "vts"],
target_required: [
"block_device_writer_module",

View File

@ -21,10 +21,10 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.RootPermissionTest;
import com.android.fsverity.AddFsVerityCertRule;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
@ -35,6 +35,7 @@ import com.android.tradefed.util.CommandStatus;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -85,40 +86,25 @@ public class ApkVerityTest extends BaseHostJUnit4Test {
private static final String DAMAGING_EXECUTABLE = "/data/local/tmp/block_device_writer";
private static final String CERT_PATH = "/data/local/tmp/ApkVerityTestCert.der";
private static final String APK_VERITY_STANDARD_MODE = "2";
/** Only 4K page is supported by fs-verity currently. */
private static final int FSVERITY_PAGE_SIZE = 4096;
@Rule
public final AddFsVerityCertRule mAddFsVerityCertRule =
new AddFsVerityCertRule(this, CERT_PATH);
private ITestDevice mDevice;
private String mKeyId;
@Before
public void setUp() throws DeviceNotAvailableException {
mDevice = getDevice();
String apkVerityMode = mDevice.getProperty("ro.apk_verity.mode");
assumeTrue(mDevice.getLaunchApiLevel() >= 30
|| APK_VERITY_STANDARD_MODE.equals(apkVerityMode));
mKeyId = expectRemoteCommandToSucceed(
"mini-keyctl padd asymmetric fsv_test .fs-verity < " + CERT_PATH).trim();
if (!mKeyId.matches("^\\d+$")) {
String keyId = mKeyId;
mKeyId = null;
fail("Key ID is not decimal: " + keyId);
}
uninstallPackage(TARGET_PACKAGE);
}
@After
public void tearDown() throws DeviceNotAvailableException {
uninstallPackage(TARGET_PACKAGE);
if (mKeyId != null) {
expectRemoteCommandToSucceed("mini-keyctl unlink " + mKeyId + " .fs-verity");
}
}
@Test

View File

@ -0,0 +1,30 @@
// 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.
java_test_host {
name: "UpdatableSystemFontTest",
srcs: ["src/**/*.java"],
libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"],
static_libs: ["frameworks-base-hostutils"],
test_suites: ["general-tests", "vts"],
data: [
":NotoColorEmojiTtf",
":UpdatableSystemFontTestCertDer",
":UpdatableSystemFontTestNotoColorEmojiTtfFsvSig",
":UpdatableSystemFontTestNotoColorEmojiV1Ttf",
":UpdatableSystemFontTestNotoColorEmojiV1TtfFsvSig",
":UpdatableSystemFontTestNotoColorEmojiV2Ttf",
":UpdatableSystemFontTestNotoColorEmojiV2TtfFsvSig",
],
}

View File

@ -0,0 +1,36 @@
<?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.
-->
<configuration description="Updatable system font integration/regression test">
<option name="test-suite-tag" value="apct" />
<!-- This test requires root to side load fs-verity cert. -->
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push" value="UpdatableSystemFontTestCert.der->/data/local/tmp/UpdatableSystemFontTestCert.der" />
<option name="push" value="NotoColorEmoji.ttf->/data/local/tmp/NotoColorEmoji.ttf" />
<option name="push" value="UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig" />
<option name="push" value="UpdatableSystemFontTestNotoColorEmojiV1.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV1.ttf" />
<option name="push" value="UpdatableSystemFontTestNotoColorEmojiV1.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV1.ttf.fsv_sig" />
<option name="push" value="UpdatableSystemFontTestNotoColorEmojiV2.ttf->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV2.ttf" />
<option name="push" value="UpdatableSystemFontTestNotoColorEmojiV2.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV2.ttf.fsv_sig" />
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="UpdatableSystemFontTest.jar" />
</test>
</configuration>

View File

@ -0,0 +1,156 @@
/*
* 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.
*/
package com.android.updatablesystemfont;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import android.platform.test.annotations.RootPermissionTest;
import com.android.fsverity.AddFsVerityCertRule;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Tests if fonts can be updated by 'cmd font'.
*/
@RootPermissionTest
@RunWith(DeviceJUnit4ClassRunner.class)
public class UpdatableSystemFontTest extends BaseHostJUnit4Test {
private static final String CERT_PATH = "/data/local/tmp/UpdatableSystemFontTestCert.der";
private static final Pattern PATTERN_FONT = Pattern.compile("path = ([^, \n]*)");
private static final String NOTO_COLOR_EMOJI_TTF = "NotoColorEmoji.ttf";
private static final String TEST_NOTO_COLOR_EMOJI_V1_TTF =
"/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV1.ttf";
private static final String TEST_NOTO_COLOR_EMOJI_V1_TTF_FSV_SIG =
"/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV1.ttf.fsv_sig";
private static final String TEST_NOTO_COLOR_EMOJI_V2_TTF =
"/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV2.ttf";
private static final String TEST_NOTO_COLOR_EMOJI_V2_TTF_FSV_SIG =
"/data/local/tmp/UpdatableSystemFontTestNotoColorEmojiV2.ttf.fsv_sig";
private static final String ORIGINAL_NOTO_COLOR_EMOJI_TTF =
"/data/local/tmp/NotoColorEmoji.ttf";
private static final String ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG =
"/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig";
@Rule
public final AddFsVerityCertRule mAddFsverityCertRule =
new AddFsVerityCertRule(this, CERT_PATH);
@Before
public void setUp() throws Exception {
expectRemoteCommandToSucceed("cmd font clear");
}
@After
public void tearDown() throws Exception {
expectRemoteCommandToSucceed("cmd font clear");
}
@Test
public void updateFont() throws Exception {
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_V1_TTF, TEST_NOTO_COLOR_EMOJI_V1_TTF_FSV_SIG));
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
assertThat(fontPath).startsWith("/data/fonts/files/");
}
@Test
public void updateFont_twice() throws Exception {
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_V1_TTF, TEST_NOTO_COLOR_EMOJI_V1_TTF_FSV_SIG));
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_V2_TTF, TEST_NOTO_COLOR_EMOJI_V2_TTF_FSV_SIG));
String fontPath2 = getFontPath(NOTO_COLOR_EMOJI_TTF);
assertThat(fontPath2).startsWith("/data/fonts/files/");
assertThat(fontPath2).isNotEqualTo(fontPath);
}
@Test
public void updatedFont_dataFileIsImmutableAndReadable() throws Exception {
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_V1_TTF, TEST_NOTO_COLOR_EMOJI_V1_TTF_FSV_SIG));
String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
assertThat(fontPath).startsWith("/data");
expectRemoteCommandToFail("echo -n '' >> " + fontPath);
expectRemoteCommandToSucceed("cat " + fontPath + " > /dev/null");
}
@Test
public void updateFont_invalidCert() throws Exception {
expectRemoteCommandToFail(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_V1_TTF, TEST_NOTO_COLOR_EMOJI_V2_TTF_FSV_SIG));
}
@Test
public void updateFont_downgradeFromSystem() throws Exception {
expectRemoteCommandToFail(String.format("cmd font update %s %s",
ORIGINAL_NOTO_COLOR_EMOJI_TTF, ORIGINAL_NOTO_COLOR_EMOJI_TTF_FSV_SIG));
}
@Test
public void updateFont_downgradeFromData() throws Exception {
expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_V2_TTF, TEST_NOTO_COLOR_EMOJI_V2_TTF_FSV_SIG));
expectRemoteCommandToFail(String.format("cmd font update %s %s",
TEST_NOTO_COLOR_EMOJI_V1_TTF, TEST_NOTO_COLOR_EMOJI_V1_TTF_FSV_SIG));
}
private String getFontPath(String fontFileName) throws Exception {
// TODO: add a dedicated command for testing.
String lines = expectRemoteCommandToSucceed("cmd font dump");
for (String line : lines.split("\n")) {
Matcher m = PATTERN_FONT.matcher(line);
if (m.find() && m.group(1).endsWith(fontFileName)) {
return m.group(1);
}
}
CLog.e("Font not found: " + fontFileName);
return null;
}
private String expectRemoteCommandToSucceed(String cmd) throws Exception {
CommandResult result = getDevice().executeShellV2Command(cmd);
assertWithMessage("`" + cmd + "` failed: " + result.getStderr())
.that(result.getStatus())
.isEqualTo(CommandStatus.SUCCESS);
return result.getStdout();
}
private void expectRemoteCommandToFail(String cmd) throws Exception {
CommandResult result = getDevice().executeShellV2Command(cmd);
assertWithMessage("Unexpected success from `" + cmd + "`: " + result.getStderr())
.that(result.getStatus())
.isNotEqualTo(CommandStatus.SUCCESS);
}
}

View File

@ -0,0 +1,82 @@
// 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.
filegroup {
name: "UpdatableSystemFontTestKeyPem",
srcs: ["UpdatableSystemFontTestKey.pem"],
}
filegroup {
name: "UpdatableSystemFontTestCertPem",
srcs: ["UpdatableSystemFontTestCert.pem"],
}
filegroup {
name: "UpdatableSystemFontTestCertDer",
srcs: ["UpdatableSystemFontTestCert.der"],
}
genrule_defaults {
name: "updatable_system_font_increment_font_revision_default",
tools: ["update_font_metadata"],
cmd: "$(location update_font_metadata) " +
"--input=$(in) " +
"--output=$(out) " +
"--revision=+1",
}
genrule {
name: "UpdatableSystemFontTestNotoColorEmojiV1Ttf",
defaults: ["updatable_system_font_increment_font_revision_default"],
srcs: [":NotoColorEmojiTtf"],
out: ["UpdatableSystemFontTestNotoColorEmojiV1.ttf"],
}
genrule {
name: "UpdatableSystemFontTestNotoColorEmojiV2Ttf",
defaults: ["updatable_system_font_increment_font_revision_default"],
srcs: [":UpdatableSystemFontTestNotoColorEmojiV1Ttf"],
out: ["UpdatableSystemFontTestNotoColorEmojiV2.ttf"],
}
genrule_defaults {
name: "updatable_system_font_sig_gen_default",
tools: ["fsverity"],
tool_files: [":UpdatableSystemFontTestKeyPem", ":UpdatableSystemFontTestCertPem"],
cmd: "$(location fsverity) sign $(in) $(out) " +
"--key=$(location :UpdatableSystemFontTestKeyPem) " +
"--cert=$(location :UpdatableSystemFontTestCertPem) " +
"> /dev/null",
}
genrule {
name: "UpdatableSystemFontTestNotoColorEmojiTtfFsvSig",
defaults: ["updatable_system_font_sig_gen_default"],
srcs: [":NotoColorEmojiTtf"],
out: ["UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig"],
}
genrule {
name: "UpdatableSystemFontTestNotoColorEmojiV1TtfFsvSig",
defaults: ["updatable_system_font_sig_gen_default"],
srcs: [":UpdatableSystemFontTestNotoColorEmojiV1Ttf"],
out: ["UpdatableSystemFontTestNotoColorEmojiV1.ttf.fsv_sig"],
}
genrule {
name: "UpdatableSystemFontTestNotoColorEmojiV2TtfFsvSig",
defaults: ["updatable_system_font_sig_gen_default"],
srcs: [":UpdatableSystemFontTestNotoColorEmojiV2Ttf"],
out: ["UpdatableSystemFontTestNotoColorEmojiV2.ttf.fsv_sig"],
}

View File

@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFOTCCAyGgAwIBAgIUFaI1D5NtwkCVM3G4bFZ6sQSb598wDQYJKoZIhvcNAQEL
BQAwLDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRAwDgYDVQQKDAdBbmRyb2lk
MB4XDTIxMDIwMTA3MzAyNFoXDTIxMDMwMzA3MzAyNFowLDELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAkNBMRAwDgYDVQQKDAdBbmRyb2lkMIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEA0U1zptc41E65ooeBPD33Mjgp6cYPydyj2Acq80Xy7lP7
d6/2t6w7nNNl2x3n8dAhOl3de3IxTp6JI2SdoRb7obfcp+hWJoo/cxnHpr3q/u4R
KED0rmWaOVHpGbajSTFZgN+cTbTKJbgtXm/H65x1QfO18ep/vj5fRiu1xPpJqDv/
xuvuko2U3eC2+NayxzCWXVFrKPLx8GvzSQ3Utaug17vs7/5GqkRJgq3lk4DvmjNA
vY8YA4RAkII1sSaceAWFEG6ztENLu2kjcxAI9qHxxBwQZit/NtFVlFGqSN3MEYjS
M9Fz04RsUxF672QJpAgwCJDZ41rdB3hkHvOUK9PcepBsHdZq9cQ+E64+TX+jsJLu
VouViKlYr6WYjvhfqZeRhwbj7CoEZ2DyEZKrl27fgWaidUT5LGEQLVxg90ymbimI
6UwXRUwmRBQJBdRO4RGvngtqxRuamyjAKDDHx5YccXCX4FWLUypyQlz0asojvbJZ
Og7DFa1qsRdGrGIRoQJ8pYnAjBJfSudr1l0mR7fZSfZc0W9ZmuROWx9Ip7aJWQnQ
8JLtbNPuFLD2qbmg9Y1lcXJp1FvI9FcM8JsBqZNEANQwwsdTaa8gw+3W6J2SXKQP
H+yZI/fJWWWRFADtqmpxtvXK9K+Cy1HQmg7D0IIxVPp8rrbz6TGrg+R3/N9FBWMC
AwEAAaNTMFEwHQYDVR0OBBYEFDS48o2UAstoOyLMcgamHKrZdl3cMB8GA1UdIwQY
MBaAFDS48o2UAstoOyLMcgamHKrZdl3cMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
hvcNAQELBQADggIBAF7taBYAe20tWZu0pY9d4Z8il4LoJcRrKF4YiA02UizErgCF
h4iECy6+pcu7DJUfvCh3dCWE7CDG+OnfUWTwEHVG9n8XI/ydetBUG76PZwTadI7B
gzJ1y7/vWqJo5U6ki+sXNmq3hkgNsNZgza3LpdovkWJYeRdffM6m/bimzwYx9id8
5mKw2PcbVZcb25r+0dCoLVJsqqCoRjdYUy/MKPutWG2bPzmaIv8KsKFN+mzlwhJH
lpJ/LR+3NoaHrOCFG7CW/2Ihe501vmdQ2m/VKosyk0igw8WmTsY6xMbw2t77yKkD
hnJr1NbhKeEV9gAB2BFX8nRWI7NTgp8fG78YLVz1UcbIHmYLgFoc3ezyma+CoR86
ER20lKd4+TNnz4RtaPdZlBa0Ba3bsMtEneqlrHvcPrZ5tgGsQR9+cy3ZtTZ/LUQX
+Xuj/EoJXuuB3hkhg52zawN5n7WUe8efWHcv1jHqeIj0phcgbZ6u4fFBPsYjzDKe
VuYHXglNOchmoBQwEaJI/TCiEgI8dcSJXSquLAXrtznVnxzT46ZMEt5LaW1/1NLx
q//yoPdolCI0lpunh5jvIZJpUl5XMjxVSyaveQDNVqJkITWzWqIxAT5yTLtkCNlW
c1XyzeHkpMItiJtBruExmnaTmNjlVKsXP8wQFOYbDGgXY5iHIMbgovptRyH/
-----END CERTIFICATE-----

View File

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDRTXOm1zjUTrmi
h4E8PfcyOCnpxg/J3KPYByrzRfLuU/t3r/a3rDuc02XbHefx0CE6Xd17cjFOnokj
ZJ2hFvuht9yn6FYmij9zGcemver+7hEoQPSuZZo5UekZtqNJMVmA35xNtMoluC1e
b8frnHVB87Xx6n++Pl9GK7XE+kmoO//G6+6SjZTd4Lb41rLHMJZdUWso8vHwa/NJ
DdS1q6DXu+zv/kaqREmCreWTgO+aM0C9jxgDhECQgjWxJpx4BYUQbrO0Q0u7aSNz
EAj2ofHEHBBmK3820VWUUapI3cwRiNIz0XPThGxTEXrvZAmkCDAIkNnjWt0HeGQe
85Qr09x6kGwd1mr1xD4Trj5Nf6Owku5Wi5WIqVivpZiO+F+pl5GHBuPsKgRnYPIR
kquXbt+BZqJ1RPksYRAtXGD3TKZuKYjpTBdFTCZEFAkF1E7hEa+eC2rFG5qbKMAo
MMfHlhxxcJfgVYtTKnJCXPRqyiO9slk6DsMVrWqxF0asYhGhAnylicCMEl9K52vW
XSZHt9lJ9lzRb1ma5E5bH0intolZCdDwku1s0+4UsPapuaD1jWVxcmnUW8j0Vwzw
mwGpk0QA1DDCx1NpryDD7dbonZJcpA8f7Jkj98lZZZEUAO2qanG29cr0r4LLUdCa
DsPQgjFU+nyutvPpMauD5Hf830UFYwIDAQABAoICAQCTVTcFCdl6MdSg4UwK0P/S
fRCb/A0fJs67Agis6N9h/wI0NUyx7G6mLXU0si+U29KYGH0RKcgltJmKrYf8XoZR
R3DvTTBfvs99QXd2G5hxTboMIPVcUi8nDE7PB+6XVkLP4hhP5uSpeqWNJZiQdTlh
bKH2IgE8NQGyDpDMkPcKkvmw2GG/DiTtrwJ91fxRFRWzqN2LHMFMYWEHWtIR9Der
xSC7q72om5s3fxvtIkUHwe5fwXvA9fbRAqezBR/9qL0LXTHowbpsuUz38SCuJD9g
sfSlRxcsyly4pGf/FQpSiYKWcWlcSopKSzLDkyLqMc1GKlkGnu6aFJg95W63D1LS
OaOXuYShHxLkqyhT8uQGRqDCu3E2ivb6fMxAPzJxxs3JrZvumNsqyxbp+HVF0idj
NijMN/8Kb4KmNHG9I3SHG61tQFYDtxoMMNiHzq3fafBJnVcf6iThQdE5pGLN2OdF
3rcSTeHI2HxhTrXtuiHmWXNk9aZ2TOhrssNZZjDkFL/KYh6G8guy+tn66YWy77VC
id+6PBzYXTXsUauo4NWW1rLUfzT/y93IwVGpoXs7GHUUduZ6Q3PxsMTMF9IjBvqR
JvfP84CUfGXoebVJmWyGhtW6N5ParvQxbonDitA0TPZcRyX3N8yqIGO/mb8MWA9M
7s/xMZuksOpw5LSCoTAW6QKCAQEA9Z1WM/5XT+5HkwPBvS5aRz0SqMqPxAkZ0dNz
O06zpXv6e2IPy40UzFWCIkyq3vWKQ5bqU1fnejUdmjvtnP+KhH6fxnQCgiunnrDq
j1Sk2Y4gb1KyZY/C8IejOexM2qX7sfDTLI8XEvxJxVFCNmvYfnv4AX5QD8VOsjrg
bvodLAgDSo2FVDP+mkpW7zAIoRV02l6QdZA+YcG940eqxB9sPR3/1KUHe9wUTTbJ
FV5ahEPuXCyvRJkZ/rD5CPPZoQHfjKHxDlu7yfoatzCSYj10R+RInfqOFGVY4D/C
2csXjymwTN4CFUnJcP410YhPFn5ekmc/E3xqPKgIDQhQ2+oivwKCAQEA2icN1iEo
YuBJwB3pX3jrwk+1bpUXASueWhyAhSeNMrTrJ/lSgEAy9FBxJNnK1PjkABRnFhS+
uxbC2hQdfAkNDS21PQOk6hOhebUVuBdfmKY1CL+P9y4Af0fjV1rgRGHihnZB5lKU
1R/wFb8c4QgPwduiqDoZ5QP3dgxpZ4R3SCzuoyVelUSlgyWPoslg+yPddcnV8bTf
BUlEOOyXgVudkSFlRpWZ+/ZAkLTj8rnrtKp8/+GtTQvJvPJHPfuSsDhI+EQVWqab
HelMhxvIi9xOyN/OCc3Ex6JlEVa+X8EyNhQsV2sAKnld92hdEozW2uxRniIkxvL4
CuBp/p3fWxEaXQKCAQEAw2j7RYCMnNZZ8Zhiko4HW3g2mT4XpYMMHMlbe4sBGJ8L
yRBaurqzGmLJl1ph8+NsrpuqMMbWLn+F3sjhIjCZVxKbMbvopwHuaS4eYAya30/Z
dFhaAL2g/dccQSBEgQzftFGC4YeydvNsCeW9hSjGZNNinGWPcwyqsNhw6Tpq7TYu
0CjKNBTt8nlEsyYHJ4m3n2jvC+nIB+Spm+LP9Rt+9R0iBl+KFbwiFtCIqUyZPXQC
dylCBJS+fsj0SXAg7J1d6ziIXcEUJfyrNqYZQLneAriYIcBPO+DqFfgEoVyYkNk9
H9rd02wSLajCzsLhEWdW/KnSIEGzEDErvpqoIl8kZwKCAQEAjNO3T+sZyjKmCXqF
xBcogsi4BAoEzsGcuOk7Yjn1Ia2/PI/r3VUUT7l6QOLD2JZPgWmqXovH0LjR0rw3
iHHDViWSoS+wD1fa3tmyiqO0F7P7+ojHZDbzJTeAIE1PB3X1KP5AbnITGD5E25UD
DJYKrgeeSmEvhDL6Vd+PT78ozZQL/Y/LLishebcOsXS0wYsWlMpV7XHoot34R5Mb
/urond7kJRvASvJeHcxYdsHk0j1Y8kp6eIlKk0oICZBU0qOTH4m8C0gQTM/lkjay
UO9IgM5RkOyfwowoGHhZ7zClvFlrgodVlRXCPkvGAYqfzLXPvnimKzSAQW07n53E
qWIyFQKCAQAWRNG6hPCOzkNxMJ/RK7dwxZW6b4a1L3PMXTT/xrBKRIS1WNjbpkYO
/FLIufOqJT6FQN2obM5uso3TI+R7MwH8DnTSnDDy0Hvs3CdHdtn2tapZOViF/UVv
uCQa+/jMVKFCZ8k7pPFMIG6tB6WBA5MmJrW+8s0ouxLbRF5rZyzqOeyPdVBYYYDb
68nGNA6GAtTQs9h7xV2tsQ1bXNP+6gqG3BgZYo+76xKITddT6s9aaC++LVBnPOdq
LHV7gUvoBkVLjIp4L3Fb/DGMCcOVMCxmFlRBn+RBlV7slehvgq+Ywz2GHWLr+O/z
V2NAtwvCfZE2Do/4f2mpHnamhS6AvrDe
-----END PRIVATE KEY-----

View File

@ -0,0 +1,77 @@
/*
* 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.
*/
package com.android.fsverity;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assume.assumeTrue;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
import org.junit.rules.ExternalResource;
public final class AddFsVerityCertRule extends ExternalResource {
private static final String APK_VERITY_STANDARD_MODE = "2";
private final BaseHostJUnit4Test mHost;
private final String mCertPath;
private String mKeyId;
public AddFsVerityCertRule(BaseHostJUnit4Test host, String certPath) {
mHost = host;
mCertPath = certPath;
}
@Override
protected void before() throws Throwable {
ITestDevice device = mHost.getDevice();
String apkVerityMode = device.getProperty("ro.apk_verity.mode");
assumeTrue(device.getLaunchApiLevel() >= 30
|| APK_VERITY_STANDARD_MODE.equals(apkVerityMode));
String keyId = executeCommand(
"mini-keyctl padd asymmetric fsv_test .fs-verity < " + mCertPath).trim();
assertThat(keyId).matches("^\\d+$");
mKeyId = keyId;
}
@Override
protected void after() {
if (mKeyId == null) return;
try {
executeCommand("mini-keyctl unlink " + mKeyId + " .fs-verity");
} catch (DeviceNotAvailableException e) {
LogUtil.CLog.e(e);
}
mKeyId = null;
}
private String executeCommand(String cmd) throws DeviceNotAvailableException {
CommandResult result = mHost.getDevice().executeShellV2Command(cmd);
assertWithMessage("`" + cmd + "` failed: " + result.getStderr())
.that(result.getStatus())
.isEqualTo(CommandStatus.SUCCESS);
return result.getStdout();
}
}

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python
import argparse
from fontTools import ttLib
def update_font_revision(font, revisionSpec):
if revisionSpec.startswith('+'):
font['head'].fontRevision += float(revisionSpec[1:])
else:
font['head'].fontRevision = float(revisionSpec)
def main():
args_parser = argparse.ArgumentParser(description='Update font file metadata')
args_parser.add_argument('--input', help='Input otf/ttf font file.')
args_parser.add_argument('--output', help='Output file for updated font file.')
args_parser.add_argument('--revision', help='Updated font revision. Use + to update revision based on the current revision')
args = args_parser.parse_args()
font = ttLib.TTFont(args.input)
update_font_revision(font, args.revision)
font.save(args.output)
if __name__ == "__main__":
main()