• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #undef LOG_TAG
18 #define LOG_TAG "LayerTraceGenerator"
19 //#define LOG_NDEBUG 0
20 
21 #include <Tracing/TransactionProtoParser.h>
22 #include <gui/LayerState.h>
23 #include <log/log.h>
24 #include <renderengine/ExternalTexture.h>
25 #include <utils/String16.h>
26 #include <filesystem>
27 #include <fstream>
28 #include <ios>
29 #include <string>
30 #include <vector>
31 #include "FrontEnd/LayerCreationArgs.h"
32 #include "FrontEnd/RequestedLayerState.h"
33 #include "LayerProtoHelper.h"
34 #include "Tracing/LayerTracing.h"
35 #include "TransactionState.h"
36 #include "cutils/properties.h"
37 
38 #include "LayerTraceGenerator.h"
39 
40 namespace android {
41 using namespace ftl::flag_operators;
42 
generate(const proto::TransactionTraceFile & traceFile,const char * outputLayersTracePath,bool onlyLastEntry)43 bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile,
44                                    const char* outputLayersTracePath, bool onlyLastEntry) {
45     if (traceFile.entry_size() == 0) {
46         ALOGD("Trace file is empty");
47         return false;
48     }
49 
50     TransactionProtoParser parser(std::make_unique<TransactionProtoParser::FlingerDataMapper>());
51 
52     // frontend
53     frontend::LayerLifecycleManager lifecycleManager;
54     frontend::LayerHierarchyBuilder hierarchyBuilder{{}};
55     frontend::LayerSnapshotBuilder snapshotBuilder;
56     ui::DisplayMap<ui::LayerStack, frontend::DisplayInfo> displayInfos;
57 
58     renderengine::ShadowSettings globalShadowSettings{.ambientColor = {1, 1, 1, 1}};
59     char value[PROPERTY_VALUE_MAX];
60     property_get("ro.surface_flinger.supports_background_blur", value, "0");
61     bool supportsBlur = atoi(value);
62 
63     LayerTracing layerTracing;
64     layerTracing.setTraceFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS);
65     // 10MB buffer size (large enough to hold a single entry)
66     layerTracing.setBufferSize(10 * 1024 * 1024);
67     layerTracing.enable();
68     layerTracing.writeToFile(outputLayersTracePath);
69     std::ofstream out(outputLayersTracePath, std::ios::binary | std::ios::app);
70 
71     ALOGD("Generating %d transactions...", traceFile.entry_size());
72     for (int i = 0; i < traceFile.entry_size(); i++) {
73         // parse proto
74         proto::TransactionTraceEntry entry = traceFile.entry(i);
75         ALOGV("    Entry %04d/%04d for time=%" PRId64 " vsyncid=%" PRId64
76               " layers +%d -%d handles -%d transactions=%d",
77               i, traceFile.entry_size(), entry.elapsed_realtime_nanos(), entry.vsync_id(),
78               entry.added_layers_size(), entry.destroyed_layers_size(),
79               entry.destroyed_layer_handles_size(), entry.transactions_size());
80 
81         std::vector<std::unique_ptr<frontend::RequestedLayerState>> addedLayers;
82         addedLayers.reserve((size_t)entry.added_layers_size());
83         for (int j = 0; j < entry.added_layers_size(); j++) {
84             LayerCreationArgs args;
85             parser.fromProto(entry.added_layers(j), args);
86             ALOGV("       %s", args.getDebugString().c_str());
87             addedLayers.emplace_back(std::make_unique<frontend::RequestedLayerState>(args));
88         }
89 
90         std::vector<TransactionState> transactions;
91         transactions.reserve((size_t)entry.transactions_size());
92         for (int j = 0; j < entry.transactions_size(); j++) {
93             // apply transactions
94             TransactionState transaction = parser.fromProto(entry.transactions(j));
95             for (auto& resolvedComposerState : transaction.states) {
96                 if (resolvedComposerState.state.what & layer_state_t::eInputInfoChanged) {
97                     if (!resolvedComposerState.state.windowInfoHandle->getInfo()->inputConfig.test(
98                                 gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL)) {
99                         // create a fake token since the FE expects a valid token
100                         resolvedComposerState.state.windowInfoHandle->editInfo()->token =
101                                 sp<BBinder>::make();
102                     }
103                 }
104             }
105             transactions.emplace_back(std::move(transaction));
106         }
107 
108         for (int j = 0; j < entry.destroyed_layers_size(); j++) {
109             ALOGV("       destroyedHandles=%d", entry.destroyed_layers(j));
110         }
111 
112         std::vector<uint32_t> destroyedHandles;
113         destroyedHandles.reserve((size_t)entry.destroyed_layer_handles_size());
114         for (int j = 0; j < entry.destroyed_layer_handles_size(); j++) {
115             ALOGV("       destroyedHandles=%d", entry.destroyed_layer_handles(j));
116             destroyedHandles.push_back(entry.destroyed_layer_handles(j));
117         }
118 
119         bool displayChanged = entry.displays_changed();
120         if (displayChanged) {
121             parser.fromProto(entry.displays(), displayInfos);
122         }
123 
124         // apply updates
125         lifecycleManager.addLayers(std::move(addedLayers));
126         lifecycleManager.applyTransactions(transactions, /*ignoreUnknownHandles=*/true);
127         lifecycleManager.onHandlesDestroyed(destroyedHandles, /*ignoreUnknownHandles=*/true);
128 
129         if (lifecycleManager.getGlobalChanges().test(
130                     frontend::RequestedLayerState::Changes::Hierarchy)) {
131             hierarchyBuilder.update(lifecycleManager.getLayers(),
132                                     lifecycleManager.getDestroyedLayers());
133         }
134 
135         frontend::LayerSnapshotBuilder::Args args{.root = hierarchyBuilder.getHierarchy(),
136                                                   .layerLifecycleManager = lifecycleManager,
137                                                   .displays = displayInfos,
138                                                   .displayChanges = displayChanged,
139                                                   .globalShadowSettings = globalShadowSettings,
140                                                   .supportsBlur = supportsBlur,
141                                                   .forceFullDamage = false,
142                                                   .supportedLayerGenericMetadata = {},
143                                                   .genericLayerMetadataKeyMap = {}};
144         snapshotBuilder.update(args);
145 
146         bool visibleRegionsDirty = lifecycleManager.getGlobalChanges().any(
147                 frontend::RequestedLayerState::Changes::VisibleRegion |
148                 frontend::RequestedLayerState::Changes::Hierarchy |
149                 frontend::RequestedLayerState::Changes::Visibility);
150 
151         ALOGV("    layers:%04zu snapshots:%04zu changes:%s", lifecycleManager.getLayers().size(),
152               snapshotBuilder.getSnapshots().size(),
153               lifecycleManager.getGlobalChanges().string().c_str());
154 
155         lifecycleManager.commitChanges();
156 
157         LayersProto layersProto = LayerProtoFromSnapshotGenerator(snapshotBuilder, displayInfos, {},
158                                                                   layerTracing.getFlags())
159                                           .generate(hierarchyBuilder.getHierarchy());
160         auto displayProtos = LayerProtoHelper::writeDisplayInfoToProto(displayInfos);
161         if (!onlyLastEntry || (i == traceFile.entry_size() - 1)) {
162             layerTracing.notify(visibleRegionsDirty, entry.elapsed_realtime_nanos(),
163                                 entry.vsync_id(), &layersProto, {}, &displayProtos);
164             layerTracing.appendToStream(out);
165         }
166     }
167     layerTracing.disable("", /*writeToFile=*/false);
168     out.close();
169     ALOGD("End of generating trace file. File written to %s", outputLayersTracePath);
170     return true;
171 }
172 
173 } // namespace android
174