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 com.android.compatibility.common.tradefed.result.suite;
17 
18 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
19 import com.android.tradefed.config.Option;
20 import com.android.tradefed.config.OptionClass;
21 import com.android.tradefed.invoker.IInvocationContext;
22 import com.android.tradefed.invoker.InvocationContext;
23 import com.android.tradefed.invoker.tracing.CloseableTraceScope;
24 import com.android.tradefed.log.LogUtil.CLog;
25 import com.android.tradefed.result.ITestInvocationListener;
26 import com.android.tradefed.result.ITestSummaryListener;
27 import com.android.tradefed.result.proto.FileProtoResultReporter;
28 import com.android.tradefed.result.proto.ProtoResultParser;
29 import com.android.tradefed.util.FileUtil;
30 import com.android.tradefed.util.IDisableable;
31 
32 import java.io.File;
33 import java.io.IOException;
34 
35 /**
36  * This reporter compacts together all the partial proto to save disk space. This is a memory heavy
37  * operation so it's executed last and can optionally fail and be inop (resulting in no
38  * compression).
39  */
40 @OptionClass(alias = "result-reporter")
41 public class CompactProtoReporter
42         implements ITestInvocationListener, ITestSummaryListener, IDisableable {
43 
44     @Option(
45             name = "skip-proto-compacting",
46             description = "Option to disable compacting the protos at the end")
47     private boolean mSkipProtoCompacting = false;
48 
49     @Option(name = "disable", description = "Whether or not to disable this reporter.")
50     private boolean mDisable = false;
51 
52     private CompatibilityBuildHelper mBuildHelper;
53 
54     /** The directory containing the proto results */
55     private File mResultDir = null;
56 
57     private File mBaseProtoFile = null;
58 
59     @Override
invocationStarted(IInvocationContext context)60     public void invocationStarted(IInvocationContext context) {
61         if (mBuildHelper == null) {
62             mBuildHelper = new CompatibilityBuildHelper(context.getBuildInfos().get(0));
63             mResultDir = CompatibilityProtoResultReporter.getProtoResultDirectory(mBuildHelper);
64             mBaseProtoFile = new File(mResultDir, CompatibilityProtoResultReporter.PROTO_FILE_NAME);
65         }
66     }
67 
68     @Override
invocationEnded(long elapsedTime)69     public void invocationEnded(long elapsedTime) {
70         if (mSkipProtoCompacting) {
71             return;
72         }
73         if (mBuildHelper == null) {
74             CLog.w("Something went wrong and no build helper are configured.");
75             return;
76         }
77         // Compact all the protos
78         try (CloseableTraceScope ignored = new CloseableTraceScope("compact_protos")) {
79             CLog.d("Compacting protos to reduce disk size");
80             compactAllProtos();
81             CLog.d("Done compacting protos");
82         } catch (RuntimeException e) {
83             CLog.e("Failed to compact the protos");
84             CLog.e(e);
85             FileUtil.deleteFile(mBaseProtoFile);
86             return;
87         }
88         // Delete all the protos we compacted
89         int index = 0;
90         while (new File(mBaseProtoFile.getAbsolutePath() + index).exists()) {
91             FileUtil.deleteFile(new File(mBaseProtoFile.getAbsolutePath() + index));
92             index++;
93         }
94     }
95 
compactAllProtos()96     private void compactAllProtos() {
97         FileProtoResultReporter fprr = new FileProtoResultReporter();
98         fprr.setFileOutput(mBaseProtoFile);
99         ProtoResultParser parser = new ProtoResultParser(fprr, new InvocationContext(), true);
100         int index = 0;
101         while (new File(mBaseProtoFile.getAbsolutePath() + index).exists()) {
102             try {
103                 parser.processFileProto(new File(mBaseProtoFile.getAbsolutePath() + index));
104             } catch (IOException e) {
105                 throw new RuntimeException(e);
106             }
107             index++;
108         }
109     }
110 
111     @Override
isDisabled()112     public boolean isDisabled() {
113         return mDisable;
114     }
115 }
116