1 /*
2  * Copyright (C) 2019 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 com.android.cts.net.hostside;
17 
18 import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
19 import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG;
20 
21 import android.os.Environment;
22 import android.os.FileUtils;
23 import android.os.ParcelFileDescriptor;
24 import android.util.Log;
25 
26 import com.android.compatibility.common.util.OnFailureRule;
27 
28 import org.junit.AssumptionViolatedException;
29 import org.junit.runner.Description;
30 import org.junit.runners.model.Statement;
31 
32 import java.io.File;
33 import java.io.FileInputStream;
34 import java.io.FileNotFoundException;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.nio.charset.StandardCharsets;
38 
39 import androidx.test.platform.app.InstrumentationRegistry;
40 
41 public class DumpOnFailureRule extends OnFailureRule {
42     private File mDumpDir = new File(Environment.getExternalStorageDirectory(),
43             "CtsHostsideNetworkTests");
44 
45     @Override
onTestFailure(Statement base, Description description, Throwable throwable)46     public void onTestFailure(Statement base, Description description, Throwable throwable) {
47         final String testName = description.getClassName() + "_" + description.getMethodName();
48 
49         if (throwable instanceof AssumptionViolatedException) {
50             Log.d(TAG, "Skipping test " + testName + ": " + throwable);
51             return;
52         }
53 
54         prepareDumpRootDir();
55         final File dumpFile = new File(mDumpDir, "dump-" + testName);
56         Log.i(TAG, "Dumping debug info for " + description + ": " + dumpFile.getPath());
57         try (FileOutputStream out = new FileOutputStream(dumpFile)) {
58             for (String cmd : new String[] {
59                     "dumpsys netpolicy",
60                     "dumpsys network_management",
61                     "dumpsys usagestats " + TEST_PKG,
62                     "dumpsys usagestats appstandby",
63             }) {
64                 dumpCommandOutput(out, cmd);
65             }
66         } catch (FileNotFoundException e) {
67             Log.e(TAG, "Error opening file: " + dumpFile, e);
68         } catch (IOException e) {
69             Log.e(TAG, "Error closing file: " + dumpFile, e);
70         }
71     }
72 
dumpCommandOutput(FileOutputStream out, String cmd)73     void dumpCommandOutput(FileOutputStream out, String cmd) {
74         final ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation()
75                 .getUiAutomation().executeShellCommand(cmd);
76         try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
77             out.write(("Output of '" + cmd + "':\n").getBytes(StandardCharsets.UTF_8));
78             FileUtils.copy(in, out);
79             out.write("\n\n=================================================================\n\n"
80                     .getBytes(StandardCharsets.UTF_8));
81         } catch (IOException e) {
82             Log.e(TAG, "Error dumping '" + cmd + "'", e);
83         }
84     }
85 
prepareDumpRootDir()86     void prepareDumpRootDir() {
87         if (!mDumpDir.exists() && !mDumpDir.mkdir()) {
88             Log.e(TAG, "Error creating " + mDumpDir);
89         }
90     }
91 }
92