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 import static org.junit.Assume.assumeTrue;
21 
22 import com.android.server.os.TombstoneProtos.Tombstone;
23 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
24 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
25 import com.android.tradefed.util.CommandResult;
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.InputStream;
29 import java.util.Arrays;
30 import org.junit.After;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 
35 @RunWith(DeviceJUnit4ClassRunner.class)
36 public class PermissiveMteTest extends BaseHostJUnit4Test {
37   String mUUID;
38 
39   @Before
setUp()40   public void setUp() throws Exception {
41     mUUID = java.util.UUID.randomUUID().toString();
42     CommandResult result =
43         getDevice().executeShellV2Command("/data/local/tmp/mte_crash setUp " + mUUID);
44     assumeTrue("mte_crash needs to segfault", result.getExitCode() == 139);
45   }
46 
parseTombstone(String tombstonePath)47   Tombstone parseTombstone(String tombstonePath) throws Exception {
48     File tombstoneFile = getDevice().pullFile(tombstonePath);
49     InputStream istr = new FileInputStream(tombstoneFile);
50     Tombstone tombstoneProto;
51     try {
52       tombstoneProto = Tombstone.parseFrom(istr);
53     } finally {
54       istr.close();
55     }
56     return tombstoneProto;
57   }
58 
59   @After
tearDown()60   public void tearDown() throws Exception {
61     String[] tombstones = getDevice().getChildren("/data/tombstones");
62     for (String tombstone : tombstones) {
63       if (!tombstone.endsWith(".pb")) {
64         continue;
65       }
66       String tombstonePath = "/data/tombstones/" + tombstone;
67       Tombstone tombstoneProto = parseTombstone(tombstonePath);
68       if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains(mUUID))) {
69         continue;
70       }
71       getDevice().deleteFile(tombstonePath);
72       // remove the non .pb file as well.
73       getDevice().deleteFile(tombstonePath.substring(0, tombstonePath.length() - 3));
74     }
75   }
76 
77   @Test
testCrash()78   public void testCrash() throws Exception {
79     CommandResult result = getDevice().executeShellV2Command(
80         "MTE_PERMISSIVE=1 /data/local/tmp/mte_crash testCrash " + mUUID);
81     assertThat(result.getExitCode()).isEqualTo(0);
82     int numberTombstones = 0;
83     String[] tombstones = getDevice().getChildren("/data/tombstones");
84     for (String tombstone : tombstones) {
85       if (!tombstone.endsWith(".pb")) {
86         continue;
87       }
88       String tombstonePath = "/data/tombstones/" + tombstone;
89       Tombstone tombstoneProto = parseTombstone(tombstonePath);
90       if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains(mUUID))) {
91         continue;
92       }
93       if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains("testCrash"))) {
94         continue;
95       }
96       numberTombstones++;
97     }
98     assertThat(numberTombstones).isEqualTo(1);
99   }
100   @Test
testCrashProperty()101   public void testCrashProperty() throws Exception {
102     String prevValue = getDevice().getProperty("persist.sys.mte.permissive");
103     if (prevValue == null) {
104       prevValue = "";
105     }
106     assertThat(getDevice().setProperty("persist.sys.mte.permissive", "1")).isTrue();
107     CommandResult result =
108         getDevice().executeShellV2Command("/data/local/tmp/mte_crash testCrash " + mUUID);
109     assertThat(result.getExitCode()).isEqualTo(0);
110     int numberTombstones = 0;
111     String[] tombstones = getDevice().getChildren("/data/tombstones");
112     for (String tombstone : tombstones) {
113       if (!tombstone.endsWith(".pb")) {
114         continue;
115       }
116       String tombstonePath = "/data/tombstones/" + tombstone;
117       Tombstone tombstoneProto = parseTombstone(tombstonePath);
118       if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains(mUUID))) {
119         continue;
120       }
121       if (!tombstoneProto.getCommandLineList().stream().anyMatch(x -> x.contains("testCrash"))) {
122         continue;
123       }
124       numberTombstones++;
125     }
126     assertThat(numberTombstones).isEqualTo(1);
127     assertThat(getDevice().setProperty("persist.sys.mte.permissive", prevValue)).isTrue();
128   }
129 }
130