1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tests.init;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assume.assumeTrue;
22 
23 import com.android.server.os.TombstoneProtos.Tombstone;
24 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
25 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
26 import com.android.tradefed.util.CommandResult;
27 
28 import org.junit.After;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 
33 import java.io.File;
34 import java.io.FileInputStream;
35 import java.io.InputStream;
36 import java.util.ArrayList;
37 
38 @RunWith(DeviceJUnit4ClassRunner.class)
39 public class MteUpgradeTest extends BaseHostJUnit4Test {
40     @Before
setUp()41     public void setUp() throws Exception {
42         CommandResult result =
43                 getDevice().executeShellV2Command("/system/bin/mte_upgrade_test_helper --checking");
44         assumeTrue("mte_upgrade_test_binary needs to segfault", result.getExitCode() == 139);
45     }
46 
47     @After
tearDown()48     public void tearDown() throws Exception {
49         // Easier here than in a finally in testCrash, and doesn't really hurt.
50         getDevice().executeShellV2Command("stop mte_upgrade_test_helper");
51         getDevice().executeShellV2Command("stop mte_upgrade_test_helper_overridden");
52         getDevice().setProperty("sys.mte_crash_test_uuid", "");
53     }
54 
parseTombstone(String tombstonePath)55     Tombstone parseTombstone(String tombstonePath) throws Exception {
56         File tombstoneFile = getDevice().pullFile(tombstonePath);
57         InputStream istr = new FileInputStream(tombstoneFile);
58         Tombstone tombstoneProto;
59         try {
60             tombstoneProto = Tombstone.parseFrom(istr);
61         } finally {
62             istr.close();
63         }
64         return tombstoneProto;
65     }
66 
67     @Test
testCrash()68     public void testCrash() throws Exception {
69         String uuid = java.util.UUID.randomUUID().toString();
70         getDevice().reboot();
71         assertThat(getDevice().setProperty("sys.mte_crash_test_uuid", uuid)).isTrue();
72 
73         CommandResult result = getDevice().executeShellV2Command("start mte_upgrade_test_helper");
74         assertThat(result.getExitCode()).isEqualTo(0);
75         java.lang.Thread.sleep(20000);
76         String[] tombstonesAfter = getDevice().getChildren("/data/tombstones");
77         ArrayList<String> segvCodeNames = new ArrayList<String>();
78         for (String tombstone : tombstonesAfter) {
79             if (!tombstone.endsWith(".pb")) {
80                 continue;
81             }
82             String tombstoneFilename = "/data/tombstones/" + tombstone;
83             Tombstone tombstoneProto = parseTombstone(tombstoneFilename);
84             if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains(uuid))) {
85                 continue;
86             }
87             assertThat(tombstoneProto.getSignalInfo().getName()).isEqualTo("SIGSEGV");
88             segvCodeNames.add(tombstoneProto.getSignalInfo().getCodeName());
89             getDevice().deleteFile(tombstoneFilename);
90             // remove the non .pb file as well.
91             getDevice().deleteFile(tombstoneFilename.substring(0, tombstoneFilename.length() - 3));
92         }
93         assertThat(segvCodeNames.size()).isAtLeast(3);
94         assertThat(segvCodeNames.get(0)).isEqualTo("SEGV_MTEAERR");
95         assertThat(segvCodeNames.get(1)).isEqualTo("SEGV_MTESERR");
96         assertThat(segvCodeNames.get(2)).isEqualTo("SEGV_MTEAERR");
97     }
98 
99     @Test
testCrashOverridden()100     public void testCrashOverridden() throws Exception {
101         String uuid = java.util.UUID.randomUUID().toString();
102         getDevice().reboot();
103         assertThat(getDevice().setProperty("sys.mte_crash_test_uuid", uuid)).isTrue();
104 
105         CommandResult result =
106                 getDevice().executeShellV2Command("start mte_upgrade_test_helper_overridden");
107         assertThat(result.getExitCode()).isEqualTo(0);
108         java.lang.Thread.sleep(20000);
109         String[] tombstonesAfter = getDevice().getChildren("/data/tombstones");
110         ArrayList<String> segvCodeNames = new ArrayList<String>();
111         for (String tombstone : tombstonesAfter) {
112             if (!tombstone.endsWith(".pb")) {
113                 continue;
114             }
115             String tombstoneFilename = "/data/tombstones/" + tombstone;
116             Tombstone tombstoneProto = parseTombstone(tombstoneFilename);
117             if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains(uuid))) {
118                 continue;
119             }
120             assertThat(tombstoneProto.getSignalInfo().getName()).isEqualTo("SIGSEGV");
121             segvCodeNames.add(tombstoneProto.getSignalInfo().getCodeName());
122             getDevice().deleteFile(tombstoneFilename);
123             // remove the non .pb file as well.
124             getDevice().deleteFile(tombstoneFilename.substring(0, tombstoneFilename.length() - 3));
125         }
126         assertThat(segvCodeNames.size()).isAtLeast(3);
127         assertThat(segvCodeNames.get(0)).isEqualTo("SEGV_MTEAERR");
128         assertThat(segvCodeNames.get(1)).isEqualTo("SEGV_MTEAERR");
129         assertThat(segvCodeNames.get(2)).isEqualTo("SEGV_MTEAERR");
130     }
131 
132     @Test
testDowngrade()133     public void testDowngrade() throws Exception {
134         CommandResult result =
135                 getDevice()
136                         .executeShellV2Command(
137                                 "MEMTAG_OPTIONS=async BIONIC_MEMTAG_UPGRADE_SECS=5"
138                                         + " /system/bin/mte_upgrade_test_helper --check-downgrade");
139         assertThat(result.getExitCode()).isEqualTo(0);
140     }
141 
142     @Test
testAppProcess()143     public void testAppProcess() throws Exception {
144         CommandResult result =
145                 getDevice()
146                         .executeShellV2Command(
147                                 "MEMTAG_OPTIONS=async BIONIC_MEMTAG_UPGRADE_SECS=5"
148                                         + " /data/local/tmp/app_process64 --get-mode");
149         assertThat(result.getExitCode()).isEqualTo(1);  // ASYNC
150     }
151 }
152