xref: /aosp_15_r20/platform_testing/libraries/health/rules/src/android/platform/test/rule/CrashDetector.java (revision dd0948b35e70be4c0246aabd6c72554a5eb8b22a)
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 package android.platform.test.rule;
17 
18 import android.util.Log;
19 
20 import androidx.test.InstrumentationRegistry;
21 import androidx.test.uiautomator.UiDevice;
22 
23 import org.junit.rules.TestRule;
24 import org.junit.runner.Description;
25 import org.junit.runners.model.Statement;
26 
27 import java.io.IOException;
28 
29 /** A rule that fails if the specified package crashed during the test. */
30 public class CrashDetector implements TestRule {
31     private static final String TAG = CrashDetector.class.getSimpleName();
32     private String mExpectedPid;
33     private final UiDevice mDevice;
34     private final String mPackageName;
35 
CrashDetector(String packageName)36     public CrashDetector(String packageName) {
37         mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
38         mPackageName = packageName;
39     }
40 
getPackagePid()41     private String getPackagePid() throws IOException {
42         return mDevice.executeShellCommand("pidof " + mPackageName).replaceAll("\\s", "");
43     }
44 
45     @Override
apply(Statement base, Description description)46     public Statement apply(Statement base, Description description) {
47         return new Statement() {
48             @Override
49             public void evaluate() throws Throwable {
50                 mExpectedPid = getPackagePid();
51                 Log.d(TAG, "Enter, PID=" + mExpectedPid);
52                 try {
53                     base.evaluate();
54                 } catch (Throwable t) {
55                     detectCrash(t);
56                     throw t;
57                 }
58                 detectCrash(null);
59             }
60 
61             private void detectCrash(Throwable cause) throws IOException {
62                 final String newPid = getPackagePid();
63                 if (!mExpectedPid.equals(newPid)) {
64                     throw new AssertionError(
65                             mPackageName
66                                     + " crashed, old pid= "
67                                     + mExpectedPid
68                                     + " , new pid="
69                                     + newPid,
70                             cause);
71                 }
72             }
73         };
74     }
75 
76     public void onLegitimatePackageRestart() {
77         try {
78             mExpectedPid = getPackagePid();
79             Log.d(TAG, "onLegitimatePackageRestart, PID=" + mExpectedPid);
80         } catch (IOException e) {
81             throw new RuntimeException(e);
82         }
83     }
84 }
85