• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.internal.inputmethod;
18 
19 import static android.tracing.perfetto.DataSourceParams.PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.internal.perfetto.protos.Inputmethodeditor.InputMethodClientsTraceProto;
24 import android.internal.perfetto.protos.Inputmethodeditor.InputMethodManagerServiceTraceProto;
25 import android.internal.perfetto.protos.Inputmethodeditor.InputMethodServiceTraceProto;
26 import android.internal.perfetto.protos.TracePacketOuterClass.TracePacket;
27 import android.internal.perfetto.protos.WinscopeExtensionsImplOuterClass.WinscopeExtensionsImpl;
28 import android.os.SystemClock;
29 import android.os.Trace;
30 import android.tracing.inputmethod.InputMethodDataSource;
31 import android.tracing.perfetto.DataSourceParams;
32 import android.tracing.perfetto.InitArguments;
33 import android.tracing.perfetto.Producer;
34 import android.util.proto.ProtoOutputStream;
35 import android.view.inputmethod.InputMethodManager;
36 
37 import java.io.PrintWriter;
38 import java.util.concurrent.atomic.AtomicBoolean;
39 import java.util.concurrent.atomic.AtomicInteger;
40 
41 /**
42  * An implementation of {@link ImeTracing} for perfetto tracing.
43  */
44 final class ImeTracingPerfettoImpl extends ImeTracing {
45     private final AtomicInteger mTracingSessionsCount = new AtomicInteger(0);
46     private final AtomicBoolean mIsClientDumpInProgress = new AtomicBoolean(false);
47     private final AtomicBoolean mIsServiceDumpInProgress = new AtomicBoolean(false);
48     private final AtomicBoolean mIsManagerServiceDumpInProgress = new AtomicBoolean(false);
49     private final InputMethodDataSource mDataSource = new InputMethodDataSource(
50             mTracingSessionsCount::incrementAndGet,
51             mTracingSessionsCount::decrementAndGet);
52 
ImeTracingPerfettoImpl()53     ImeTracingPerfettoImpl() {
54         Producer.init(InitArguments.DEFAULTS);
55         DataSourceParams params =
56                 new DataSourceParams.Builder()
57                         .setBufferExhaustedPolicy(
58                                 PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_STALL_AND_ABORT)
59                         .setNoFlush(true)
60                         .setWillNotifyOnStop(false)
61                         .build();
62         mDataSource.register(params);
63     }
64 
65 
66     @Override
triggerClientDump(String where, InputMethodManager immInstance, @Nullable byte[] icProto)67     public void triggerClientDump(String where, InputMethodManager immInstance,
68             @Nullable byte[] icProto) {
69         if (!isEnabled() || !isAvailable()) {
70             return;
71         }
72 
73         if (!mIsClientDumpInProgress.compareAndSet(false, true)) {
74             return;
75         }
76 
77         if (immInstance == null) {
78             return;
79         }
80 
81         try {
82             Trace.beginSection("inputmethod_client_dump");
83             mDataSource.trace((ctx) -> {
84                 final ProtoOutputStream os = ctx.newTracePacket();
85                 os.write(TracePacket.TIMESTAMP, SystemClock.elapsedRealtimeNanos());
86                 final long tokenWinscopeExtensions =
87                         os.start(TracePacket.WINSCOPE_EXTENSIONS);
88                 final long tokenExtensionsField =
89                         os.start(WinscopeExtensionsImpl.INPUTMETHOD_CLIENTS);
90                 os.write(InputMethodClientsTraceProto.WHERE, where);
91                 final long tokenClient =
92                         os.start(InputMethodClientsTraceProto.CLIENT);
93                 immInstance.dumpDebug(os, icProto);
94                 os.end(tokenClient);
95                 os.end(tokenExtensionsField);
96                 os.end(tokenWinscopeExtensions);
97             });
98         } finally {
99             mIsClientDumpInProgress.set(false);
100             Trace.endSection();
101         }
102     }
103 
104     @Override
triggerServiceDump(String where, @NonNull ServiceDumper dumper, @Nullable byte[] icProto)105     public void triggerServiceDump(String where,
106             @NonNull ServiceDumper dumper, @Nullable byte[] icProto) {
107         if (!isEnabled() || !isAvailable()) {
108             return;
109         }
110 
111         if (!mIsServiceDumpInProgress.compareAndSet(false, true)) {
112             return;
113         }
114 
115         try {
116             Trace.beginSection("inputmethod_service_dump");
117             mDataSource.trace((ctx) -> {
118                 final ProtoOutputStream os = ctx.newTracePacket();
119                 os.write(TracePacket.TIMESTAMP, SystemClock.elapsedRealtimeNanos());
120                 final long tokenWinscopeExtensions =
121                         os.start(TracePacket.WINSCOPE_EXTENSIONS);
122                 final long tokenExtensionsField =
123                         os.start(WinscopeExtensionsImpl.INPUTMETHOD_SERVICE);
124                 os.write(InputMethodServiceTraceProto.WHERE, where);
125                 dumper.dumpToProto(os, icProto);
126                 os.end(tokenExtensionsField);
127                 os.end(tokenWinscopeExtensions);
128             });
129         } finally {
130             mIsServiceDumpInProgress.set(false);
131             Trace.endSection();
132         }
133     }
134 
135     @Override
triggerManagerServiceDump(@onNull String where, @NonNull ServiceDumper dumper)136     public void triggerManagerServiceDump(@NonNull String where, @NonNull ServiceDumper dumper) {
137         if (!isEnabled() || !isAvailable()) {
138             return;
139         }
140 
141         if (!mIsManagerServiceDumpInProgress.compareAndSet(false, true)) {
142             return;
143         }
144 
145         try {
146             Trace.beginSection("inputmethod_manager_service_dump");
147             mDataSource.trace((ctx) -> {
148                 final ProtoOutputStream os = ctx.newTracePacket();
149                 os.write(TracePacket.TIMESTAMP, SystemClock.elapsedRealtimeNanos());
150                 final long tokenWinscopeExtensions =
151                         os.start(TracePacket.WINSCOPE_EXTENSIONS);
152                 final long tokenExtensionsField =
153                         os.start(WinscopeExtensionsImpl.INPUTMETHOD_MANAGER_SERVICE);
154                 os.write(InputMethodManagerServiceTraceProto.WHERE, where);
155                 dumper.dumpToProto(os, null);
156                 os.end(tokenExtensionsField);
157                 os.end(tokenWinscopeExtensions);
158             });
159         } finally {
160             mIsManagerServiceDumpInProgress.set(false);
161             Trace.endSection();
162         }
163     }
164 
165     @Override
isEnabled()166     public boolean isEnabled() {
167         return mTracingSessionsCount.get() > 0;
168     }
169 
170     @Override
startTrace(@ullable PrintWriter pw)171     public void startTrace(@Nullable PrintWriter pw) {
172         // Intentionally left empty. Tracing start/stop is managed through Perfetto.
173     }
174 
175     @Override
stopTrace(@ullable PrintWriter pw)176     public void stopTrace(@Nullable PrintWriter pw) {
177         // Intentionally left empty. Tracing start/stop is managed through Perfetto.
178     }
179 
180     @Override
addToBuffer(ProtoOutputStream proto, int source)181     public void addToBuffer(ProtoOutputStream proto, int source) {
182         // Intentionally left empty. Only used for legacy tracing.
183     }
184 }
185