diff options
| author | 2020-01-29 05:04:48 +0000 | |
|---|---|---|
| committer | 2020-01-29 05:04:48 +0000 | |
| commit | 75f5bf33b087bd12c9b791962fef3fe43b096004 (patch) | |
| tree | 794810c6017106259fc0c11d49871c2fa28715b3 | |
| parent | 11dbc1bb402a4d315289f30c44bc448eea0f74ad (diff) | |
| parent | a657ac9ca5e0c634fa5e0fe83aeea42bfedb2de3 (diff) | |
Merge changes from topic "winscope-sysui"
* changes:
Add initial SysUI trace support
Update trace buffer to support SysUI & Launcher
21 files changed, 686 insertions, 49 deletions
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index a2736333383e..21067127a8e7 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -210,4 +210,14 @@ oneway interface IStatusBar * Cancels toast with token {@code token} in {@code packageName}. */ void hideToast(String packageName, IBinder token); + + /** + * Notifies SystemUI to start tracing. + */ + void startTracing(); + + /** + * Notifies SystemUI to stop tracing. + */ + void stopTracing(); } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 7622883326a0..5ce83c2db44d 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -124,4 +124,19 @@ interface IStatusBarService * Dismiss the warning that the device is about to go to sleep due to user inactivity. */ void dismissInattentiveSleepWarning(boolean animated); + + /** + * Notifies SystemUI to start tracing. + */ + void startTracing(); + + /** + * Notifies SystemUI to stop tracing. + */ + void stopTracing(); + + /** + * Returns whether SystemUI tracing is enabled. + */ + boolean isTracing(); } diff --git a/services/core/java/com/android/server/utils/TraceBuffer.java b/core/java/com/android/internal/util/TraceBuffer.java index 0567960e05e4..fe8a59e160bd 100644 --- a/services/core/java/com/android/server/utils/TraceBuffer.java +++ b/core/java/com/android/internal/util/TraceBuffer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.utils; +package com.android.internal.util; import android.util.proto.ProtoOutputStream; @@ -27,19 +27,87 @@ import java.io.OutputStream; import java.util.ArrayDeque; import java.util.Arrays; import java.util.Queue; +import java.util.function.Consumer; /** * Buffer used for tracing and logging. + * + * @param <P> The class type of the proto provider + * @param <S> The proto class type of the encapsulating proto + * @param <T> The proto class type of the individual entry protos in the buffer + * + * {@hide} */ -public class TraceBuffer { +public class TraceBuffer<P, S extends P, T extends P> { private final Object mBufferLock = new Object(); - private final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>(); + private final ProtoProvider<P, S, T> mProtoProvider; + private final Queue<T> mBuffer = new ArrayDeque<>(); + private final Consumer mProtoDequeuedCallback; private int mBufferUsedSize; private int mBufferCapacity; + /** + * An interface to get protos from different sources (ie. fw-proto/proto-lite/nano-proto) for + * the trace buffer. + * + * @param <P> The class type of the proto provider + * @param <S> The proto class type of the encapsulating proto + * @param <T> The proto class type of the individual protos in the buffer + */ + public interface ProtoProvider<P, S extends P, T extends P> { + /** + * @return The size of the given proto. + */ + int getItemSize(P proto); + + /** + * @return The bytes of the given proto. + */ + byte[] getBytes(P proto); + + /** + * Writes the given encapsulating proto and buffer of protos to the given output + * stream. + */ + void write(S encapsulatingProto, Queue<T> buffer, OutputStream os) throws IOException; + } + + /** + * An implementation of the ProtoProvider that uses only the framework ProtoOutputStream. + */ + private static class ProtoOutputStreamProvider implements + ProtoProvider<ProtoOutputStream, ProtoOutputStream, ProtoOutputStream> { + @Override + public int getItemSize(ProtoOutputStream proto) { + return proto.getRawSize(); + } + + @Override + public byte[] getBytes(ProtoOutputStream proto) { + return proto.getBytes(); + } + + @Override + public void write(ProtoOutputStream encapsulatingProto, Queue<ProtoOutputStream> buffer, + OutputStream os) throws IOException { + os.write(encapsulatingProto.getBytes()); + for (ProtoOutputStream protoOutputStream : buffer) { + byte[] protoBytes = protoOutputStream.getBytes(); + os.write(protoBytes); + } + } + } + public TraceBuffer(int bufferCapacity) { + this(bufferCapacity, new ProtoOutputStreamProvider(), null); + } + + public TraceBuffer(int bufferCapacity, ProtoProvider protoProvider, + Consumer<T> protoDequeuedCallback) { mBufferCapacity = bufferCapacity; + mProtoProvider = protoProvider; + mProtoDequeuedCallback = protoDequeuedCallback; resetBuffer(); } @@ -65,8 +133,8 @@ public class TraceBuffer { * @throws IllegalStateException if the element cannot be added because it is larger * than the buffer size. */ - public void add(ProtoOutputStream proto) { - int protoLength = proto.getRawSize(); + public void add(T proto) { + int protoLength = mProtoProvider.getItemSize(proto); if (protoLength > mBufferCapacity) { throw new IllegalStateException("Trace object too large for the buffer. Buffer size:" + mBufferCapacity + " Object size: " + protoLength); @@ -79,26 +147,22 @@ public class TraceBuffer { } } - boolean contains(byte[] other) { + @VisibleForTesting + public boolean contains(byte[] other) { return mBuffer.stream() - .anyMatch(p -> Arrays.equals(p.getBytes(), other)); + .anyMatch(p -> Arrays.equals(mProtoProvider.getBytes(p), other)); } /** - * Writes the trace buffer to disk inside the encapsulatingProto.. + * Writes the trace buffer to disk inside the encapsulatingProto. */ - public void writeTraceToFile(File traceFile, ProtoOutputStream encapsulatingProto) + public void writeTraceToFile(File traceFile, S encapsulatingProto) throws IOException { synchronized (mBufferLock) { traceFile.delete(); try (OutputStream os = new FileOutputStream(traceFile)) { traceFile.setReadable(true /* readable */, false /* ownerOnly */); - os.write(encapsulatingProto.getBytes()); - for (ProtoOutputStream protoOutputStream : mBuffer) { - encapsulatingProto = protoOutputStream; - byte[] protoBytes = encapsulatingProto.getBytes(); - os.write(protoBytes); - } + mProtoProvider.write(encapsulatingProto, mBuffer, os); os.flush(); } } @@ -115,12 +179,16 @@ public class TraceBuffer { while (availableSpace < protoLength) { - ProtoOutputStream item = mBuffer.poll(); + P item = mBuffer.poll(); if (item == null) { throw new IllegalStateException("No element to discard from buffer"); } - mBufferUsedSize -= item.getRawSize(); + mBufferUsedSize -= mProtoProvider.getItemSize(item); availableSpace = getAvailableSpace(); + + if (mProtoDequeuedCallback != null) { + mProtoDequeuedCallback.accept(item); + } } } @@ -129,13 +197,18 @@ public class TraceBuffer { */ public void resetBuffer() { synchronized (mBufferLock) { + if (mProtoDequeuedCallback != null) { + for (T item : mBuffer) { + mProtoDequeuedCallback.accept(item); + } + } mBuffer.clear(); mBufferUsedSize = 0; } } @VisibleForTesting - int getBufferSize() { + public int getBufferSize() { return mBufferUsedSize; } @@ -144,16 +217,9 @@ public class TraceBuffer { */ public String getStatus() { synchronized (mBufferLock) { - return "Buffer size: " - + mBufferCapacity - + " bytes" - + "\n" - + "Buffer usage: " - + mBufferUsedSize - + " bytes" - + "\n" - + "Elements in the buffer: " - + mBuffer.size(); + return "Buffer size: " + mBufferCapacity + " bytes" + "\n" + + "Buffer usage: " + mBufferUsedSize + " bytes" + "\n" + + "Elements in the buffer: " + mBuffer.size(); } } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl index 577e3bbefdad..26ef1d68858e 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl @@ -27,7 +27,6 @@ oneway interface IOverviewProxy { void onInitialize(in Bundle params) = 12; - /** * @deprecated */ diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index 08996c38baf6..386fe531c93d 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -85,6 +85,8 @@ public class QuickStepContract { // The notification panel is expanded and interactive (either locked or unlocked), and the // quick settings is not expanded public static final int SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1 << 11; + // Winscope tracing is enabled + public static final int SYSUI_STATE_TRACING_ENABLED = 1 << 12; @Retention(RetentionPolicy.SOURCE) @IntDef({SYSUI_STATE_SCREEN_PINNING, @@ -98,7 +100,8 @@ public class QuickStepContract { SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED, SYSUI_STATE_OVERVIEW_DISABLED, SYSUI_STATE_HOME_DISABLED, - SYSUI_STATE_SEARCH_DISABLED + SYSUI_STATE_SEARCH_DISABLED, + SYSUI_STATE_TRACING_ENABLED }) public @interface SystemUiStateFlags {} @@ -117,6 +120,7 @@ public class QuickStepContract { str.add((flags & SYSUI_STATE_BOUNCER_SHOWING) != 0 ? "bouncer_visible" : ""); str.add((flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0 ? "a11y_click" : ""); str.add((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0 ? "a11y_long_click" : ""); + str.add((flags & SYSUI_STATE_TRACING_ENABLED) != 0 ? "tracing" : ""); return str.toString(); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java new file mode 100644 index 000000000000..557845c34bf2 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shared.tracing; + +import android.os.Trace; +import android.util.Log; +import android.view.Choreographer; + +import com.android.internal.util.TraceBuffer; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; +import java.util.function.Consumer; + +/** + * A proto tracer implementation that can be updated directly (upon state change), or on the next + * scheduled frame. + * + * @param <P> The class type of the proto provider + * @param <S> The proto class type of the encapsulating proto + * @param <T> The proto class type of the individual proto entries in the buffer + * @param <R> The proto class type of the entry root proto in the buffer + */ +public class FrameProtoTracer<P, S extends P, T extends P, R> + implements TraceBuffer.ProtoProvider<P, S, T>, Choreographer.FrameCallback { + + private static final String TAG = "FrameProtoTracer"; + private static final int BUFFER_CAPACITY = 1024 * 1024; + + private final Object mLock = new Object(); + private final TraceBuffer<P, S, T> mBuffer; + private final File mTraceFile; + private final ProtoTraceParams<P, S, T, R> mParams; + private final Choreographer mChoreographer; + private final Queue<T> mPool = new LinkedList<>(); + private final ArrayList<ProtoTraceable<R>> mTraceables = new ArrayList<>(); + private final ArrayList<ProtoTraceable<R>> mTmpTraceables = new ArrayList<>(); + + private volatile boolean mEnabled; + private boolean mFrameScheduled; + + public interface ProtoTraceParams<P, S, T, R> { + File getTraceFile(); + S getEncapsulatingTraceProto(); + T updateBufferProto(T reuseObj, ArrayList<ProtoTraceable<R>> traceables); + byte[] serializeEncapsulatingProto(S encapsulatingProto, Queue<T> buffer); + byte[] getProtoBytes(P proto); + int getProtoSize(P proto); + } + + public FrameProtoTracer(ProtoTraceParams<P, S, T, R> params) { + mParams = params; + mBuffer = new TraceBuffer<>(BUFFER_CAPACITY, this, new Consumer<T>() { + @Override + public void accept(T t) { + onProtoDequeued(t); + } + }); + mTraceFile = params.getTraceFile(); + mChoreographer = Choreographer.getMainThreadInstance(); + } + + @Override + public int getItemSize(P proto) { + return mParams.getProtoSize(proto); + } + + @Override + public byte[] getBytes(P proto) { + return mParams.getProtoBytes(proto); + } + + @Override + public void write(S encapsulatingProto, Queue<T> buffer, OutputStream os) throws IOException { + os.write(mParams.serializeEncapsulatingProto(encapsulatingProto, buffer)); + } + + public void start() { + synchronized (mLock) { + if (mEnabled) { + return; + } + mBuffer.resetBuffer(); + mEnabled = true; + } + logState(); + } + + public void stop() { + synchronized (mLock) { + if (!mEnabled) { + return; + } + mEnabled = false; + } + writeToFile(); + } + + public boolean isEnabled() { + return mEnabled; + } + + public void add(ProtoTraceable<R> traceable) { + synchronized (mLock) { + mTraceables.add(traceable); + } + } + + public void remove(ProtoTraceable<R> traceable) { + synchronized (mLock) { + mTraceables.remove(traceable); + } + } + + public void scheduleFrameUpdate() { + if (!mEnabled || mFrameScheduled) { + return; + } + + // Schedule an update on the next frame + mChoreographer.postFrameCallback(this); + mFrameScheduled = true; + } + + public void update() { + if (!mEnabled) { + return; + } + + logState(); + } + + public float getBufferUsagePct() { + return (float) mBuffer.getBufferSize() / BUFFER_CAPACITY; + } + + @Override + public void doFrame(long frameTimeNanos) { + logState(); + } + + private void onProtoDequeued(T proto) { + mPool.add(proto); + } + + private void logState() { + synchronized (mLock) { + mTmpTraceables.addAll(mTraceables); + } + + mBuffer.add(mParams.updateBufferProto(mPool.poll(), mTmpTraceables)); + mTmpTraceables.clear(); + mFrameScheduled = false; + } + + private void writeToFile() { + try { + Trace.beginSection("ProtoTracer.writeToFile"); + mBuffer.writeTraceToFile(mTraceFile, mParams.getEncapsulatingTraceProto()); + } catch (IOException e) { + Log.e(TAG, "Unable to write buffer to file", e); + } finally { + Trace.endSection(); + } + } +} + + diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/ProtoTraceable.java b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/ProtoTraceable.java new file mode 100644 index 000000000000..e05b0b074449 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/ProtoTraceable.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.shared.tracing; + +/** + * @see FrameProtoTracer + */ +public interface ProtoTraceable<T> { + + /** + * NOTE: Implementations should update all fields in this proto. + */ + void writeToProto(T proto); +} diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index aacc2c4f614b..a6be0916788b 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -117,6 +117,7 @@ import com.android.systemui.statusbar.policy.SmartReplyConstants; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.tracing.ProtoTracer; import com.android.systemui.tuner.TunablePadding.TunablePaddingService; import com.android.systemui.tuner.TunerService; import com.android.systemui.util.leak.GarbageMonitor; @@ -327,6 +328,7 @@ public class Dependency { @Inject Lazy<SystemWindows> mSystemWindows; @Inject Lazy<DisplayImeController> mDisplayImeController; @Inject Lazy<RecordingController> mRecordingController; + @Inject Lazy<ProtoTracer> mProtoTracer; @Inject public Dependency() { @@ -519,6 +521,7 @@ public class Dependency { mProviders.put(DisplayWindowController.class, mDisplayWindowController::get); mProviders.put(SystemWindows.class, mSystemWindows::get); mProviders.put(DisplayImeController.class, mDisplayImeController::get); + mProviders.put(ProtoTracer.class, mProtoTracer::get); // TODO(b/118592525): to support multi-display , we start to add something which is // per-display, while others may be global. I think it's time to add diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 79a33c926993..573ea4dd85de 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -29,6 +29,7 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WIN import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; import android.annotation.FloatRange; import android.app.ActivityTaskManager; @@ -67,6 +68,7 @@ import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.stackdivider.Divider; +import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NavigationBarController; import com.android.systemui.statusbar.phone.NavigationBarFragment; import com.android.systemui.statusbar.phone.NavigationBarView; @@ -485,7 +487,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @Inject - public OverviewProxyService(Context context, DeviceProvisionedController provisionController, + public OverviewProxyService(Context context, CommandQueue commandQueue, + DeviceProvisionedController provisionController, NavigationBarController navBarController, NavigationModeController navModeController, NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, PipUI pipUI, Optional<Divider> dividerOptional, @@ -530,6 +533,15 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis // Listen for status bar state changes statusBarWinController.registerCallback(mStatusBarWindowCallback); mScreenshotHelper = new ScreenshotHelper(context); + + // Listen for tracing state changes + commandQueue.addCallback(new CommandQueue.Callbacks() { + @Override + public void onTracingStateChanged(boolean enabled) { + mSysUiState.setFlag(SYSUI_STATE_TRACING_ENABLED, enabled) + .commitUpdate(mContext.getDisplayId()); + } + }); } public void notifyBackAction(boolean completed, int downX, int downY, boolean isButton, @@ -573,14 +585,12 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing) { - int displayId = mContext.getDisplayId(); - mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING, keyguardShowing && !keyguardOccluded) .setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED, keyguardShowing && keyguardOccluded) .setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing) - .commitUpdate(displayId); + .commitUpdate(mContext.getDisplayId()); } /** @@ -601,10 +611,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } - public float getBackButtonAlpha() { - return mNavBarButtonAlpha; - } - public void cleanupAfterDeath() { if (mInputFocusTransferStarted) { mHandler.post(()-> { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 3af3701dff97..64f083024ce1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -53,6 +53,7 @@ import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.view.AppearanceRegion; import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.policy.CallbackController; +import com.android.systemui.tracing.ProtoTracer; import java.util.ArrayList; @@ -123,6 +124,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< private static final int MSG_DISMISS_INATTENTIVE_SLEEP_WARNING = 52 << MSG_SHIFT; private static final int MSG_SHOW_TOAST = 53 << MSG_SHIFT; private static final int MSG_HIDE_TOAST = 54 << MSG_SHIFT; + private static final int MSG_TRACING_STATE_CHANGED = 55 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -143,6 +145,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< * event. */ private int mLastUpdatedImeDisplayId = INVALID_DISPLAY; + private ProtoTracer mProtoTracer; /** * These methods are called back on the main thread. @@ -325,9 +328,19 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< * @see IStatusBar#hideToast(String, IBinder) (String, IBinder) */ default void hideToast(String packageName, IBinder token) { } + + /** + * @param enabled + */ + default void onTracingStateChanged(boolean enabled) { } } public CommandQueue(Context context) { + this(context, null); + } + + public CommandQueue(Context context, ProtoTracer protoTracer) { + mProtoTracer = protoTracer; context.getSystemService(DisplayManager.class).registerDisplayListener(this, mHandler); // We always have default display. setDisabled(DEFAULT_DISPLAY, DISABLE_NONE, DISABLE2_NONE); @@ -917,6 +930,26 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } } + @Override + public void startTracing() { + synchronized (mLock) { + if (mProtoTracer != null) { + mProtoTracer.start(); + } + mHandler.obtainMessage(MSG_TRACING_STATE_CHANGED, true).sendToTarget(); + } + } + + @Override + public void stopTracing() { + synchronized (mLock) { + if (mProtoTracer != null) { + mProtoTracer.stop(); + } + mHandler.obtainMessage(MSG_TRACING_STATE_CHANGED, false).sendToTarget(); + } + } + private final class H extends Handler { private H(Looper l) { super(l); @@ -1244,6 +1277,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } break; } + case MSG_TRACING_STATE_CHANGED: + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).onTracingStateChanged((Boolean) msg.obj); + } + break; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java index ec8dbead7de2..493482aacce5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java @@ -19,6 +19,8 @@ package com.android.systemui.statusbar; import android.content.Context; import com.android.systemui.statusbar.notification.row.NotificationRowModule; +import com.android.systemui.recents.OverviewProxyService; +import com.android.systemui.tracing.ProtoTracer; import javax.inject.Singleton; @@ -35,8 +37,8 @@ public class StatusBarDependenciesModule { */ @Provides @Singleton - public CommandQueue provideCommandQueue(Context context) { - return new CommandQueue(context); + public CommandQueue provideCommandQueue(Context context, ProtoTracer protoTracer) { + return new CommandQueue(context, protoTracer); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java index 6bd122d97dea..db692c8a8c89 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java @@ -54,6 +54,10 @@ import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.SysUiStatsLog; +import com.android.systemui.shared.tracing.ProtoTraceable; +import com.android.systemui.tracing.ProtoTracer; +import com.android.systemui.tracing.nano.EdgeBackGestureHandlerProto; +import com.android.systemui.tracing.nano.SystemUiTraceProto; import java.io.PrintWriter; import java.util.concurrent.Executor; @@ -62,7 +66,7 @@ import java.util.concurrent.Executor; * Utility class to handle edge swipes for back gesture */ public class EdgeBackGestureHandler implements DisplayListener, - PluginListener<NavigationEdgeBackPlugin> { + PluginListener<NavigationEdgeBackPlugin>, ProtoTraceable<SystemUiTraceProto> { private static final String TAG = "EdgeBackGestureHandler"; private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt( @@ -161,6 +165,7 @@ public class EdgeBackGestureHandler implements DisplayListener, mMainExecutor = context.getMainExecutor(); mOverviewProxyService = overviewProxyService; mPluginManager = pluginManager; + Dependency.get(ProtoTracer.class).add(this); // Reduce the default touch slop to ensure that we can intercept the gesture // before the app starts to react to it. @@ -399,6 +404,8 @@ public class EdgeBackGestureHandler implements DisplayListener, // forward touch mEdgeBackPlugin.onMotionEvent(ev); } + + Dependency.get(ProtoTracer.class).update(); } @Override @@ -458,6 +465,14 @@ public class EdgeBackGestureHandler implements DisplayListener, pw.println(" mEdgeWidth=" + mEdgeWidth); } + @Override + public void writeToProto(SystemUiTraceProto proto) { + if (proto.edgeBackGestureHandler == null) { + proto.edgeBackGestureHandler = new EdgeBackGestureHandlerProto(); + } + proto.edgeBackGestureHandler.allowGesture = mAllowGesture; + } + class SysUiInputEventReceiver extends InputEventReceiver { SysUiInputEventReceiver(InputChannel channel, Looper looper) { super(channel, looper); diff --git a/packages/SystemUI/src/com/android/systemui/tracing/ProtoTracer.java b/packages/SystemUI/src/com/android/systemui/tracing/ProtoTracer.java new file mode 100644 index 000000000000..3bef044a2526 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tracing/ProtoTracer.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.tracing; + +import static com.android.systemui.tracing.nano.SystemUiTraceFileProto.MAGIC_NUMBER_H; +import static com.android.systemui.tracing.nano.SystemUiTraceFileProto.MAGIC_NUMBER_L; + +import android.content.Context; +import android.os.SystemClock; + +import androidx.annotation.NonNull; + +import com.android.systemui.DumpController; +import com.android.systemui.Dumpable; +import com.android.systemui.shared.tracing.FrameProtoTracer; +import com.android.systemui.shared.tracing.FrameProtoTracer.ProtoTraceParams; +import com.android.systemui.shared.tracing.ProtoTraceable; +import com.android.systemui.tracing.nano.SystemUiTraceProto; +import com.android.systemui.tracing.nano.SystemUiTraceEntryProto; +import com.android.systemui.tracing.nano.SystemUiTraceFileProto; + +import com.google.protobuf.nano.MessageNano; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Queue; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Controller for coordinating winscope proto tracing. + */ +@Singleton +public class ProtoTracer implements Dumpable, ProtoTraceParams<MessageNano, SystemUiTraceFileProto, + SystemUiTraceEntryProto, SystemUiTraceProto> { + + private static final String TAG = "ProtoTracer"; + private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L; + + private final Context mContext; + private final FrameProtoTracer<MessageNano, SystemUiTraceFileProto, SystemUiTraceEntryProto, + SystemUiTraceProto> mProtoTracer; + + @Inject + public ProtoTracer(Context context, DumpController dumpController) { + mContext = context; + mProtoTracer = new FrameProtoTracer<>(this); + dumpController.registerDumpable(this); + } + + @Override + public File getTraceFile() { + return new File(mContext.getFilesDir(), "sysui_trace.pb"); + } + + @Override + public SystemUiTraceFileProto getEncapsulatingTraceProto() { + return new SystemUiTraceFileProto(); + } + + @Override + public SystemUiTraceEntryProto updateBufferProto(SystemUiTraceEntryProto reuseObj, + ArrayList<ProtoTraceable<SystemUiTraceProto>> traceables) { + SystemUiTraceEntryProto proto = reuseObj != null + ? reuseObj + : new SystemUiTraceEntryProto(); + proto.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos(); + proto.systemUi = proto.systemUi != null ? proto.systemUi : new SystemUiTraceProto(); + for (ProtoTraceable t : traceables) { + t.writeToProto(proto.systemUi); + } + return proto; + } + + @Override + public byte[] serializeEncapsulatingProto(SystemUiTraceFileProto encapsulatingProto, + Queue<SystemUiTraceEntryProto> buffer) { + encapsulatingProto.magicNumber = MAGIC_NUMBER_VALUE; + encapsulatingProto.entry = buffer.toArray(new SystemUiTraceEntryProto[0]); + return MessageNano.toByteArray(encapsulatingProto); + } + + @Override + public byte[] getProtoBytes(MessageNano proto) { + return MessageNano.toByteArray(proto); + } + + @Override + public int getProtoSize(MessageNano proto) { + return proto.getCachedSize(); + } + + public void start() { + mProtoTracer.start(); + } + + public void stop() { + mProtoTracer.stop(); + } + + public boolean isEnabled() { + return mProtoTracer.isEnabled(); + } + + public void add(ProtoTraceable<SystemUiTraceProto> traceable) { + mProtoTracer.add(traceable); + } + + public void remove(ProtoTraceable<SystemUiTraceProto> traceable) { + mProtoTracer.remove(traceable); + } + + public void scheduleFrameUpdate() { + mProtoTracer.scheduleFrameUpdate(); + } + + public void update() { + mProtoTracer.update(); + } + + @Override + public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + pw.println("ProtoTracer:"); + pw.print(" "); pw.println("enabled: " + mProtoTracer.isEnabled()); + pw.print(" "); pw.println("usagePct: " + mProtoTracer.getBufferUsagePct()); + pw.print(" "); pw.println("file: " + getTraceFile()); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto new file mode 100644 index 000000000000..08ae99ceb7a1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; + +package com.android.systemui.tracing; + +option java_multiple_files = true; + +message SystemUiTraceProto { + + optional EdgeBackGestureHandlerProto edge_back_gesture_handler = 1; +} + +message EdgeBackGestureHandlerProto { + + optional bool allow_gesture = 1; +} diff --git a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace_file.proto b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace_file.proto new file mode 100644 index 000000000000..d1523ef13501 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace_file.proto @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; + +import "frameworks/base/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto"; + +package com.android.systemui.tracing; + +option java_multiple_files = true; + +/* represents a file full of system ui trace entries. + Encoded, it should start with 0x9 0x53 0x59 0x53 0x55 0x49 0x54 0x52 0x43 (.SYSUITRC), such + that they can be easily identified. */ +message SystemUiTraceFileProto { + + /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L + (this is needed because enums have to be 32 bits and there's no nice way to put 64bit + constants into .proto files. */ + enum MagicNumber { + INVALID = 0; + MAGIC_NUMBER_L = 0x55535953; /* SYSU (little-endian ASCII) */ + MAGIC_NUMBER_H = 0x43525449; /* ITRC (little-endian ASCII) */ + } + + optional fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */ + repeated SystemUiTraceEntryProto entry = 2; +} + +/* one system ui trace entry. */ +message SystemUiTraceEntryProto { + /* required: elapsed realtime in nanos since boot of when this entry was logged */ + optional fixed64 elapsed_realtime_nanos = 1; + + optional SystemUiTraceProto system_ui = 3; +} diff --git a/services/core/java/com/android/server/protolog/ProtoLogImpl.java b/services/core/java/com/android/server/protolog/ProtoLogImpl.java index 1653b3d2ae28..c9d42c854b54 100644 --- a/services/core/java/com/android/server/protolog/ProtoLogImpl.java +++ b/services/core/java/com/android/server/protolog/ProtoLogImpl.java @@ -38,7 +38,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.server.protolog.common.IProtoLogGroup; import com.android.server.protolog.common.LogDataType; -import com.android.server.utils.TraceBuffer; +import com.android.internal.util.TraceBuffer; import com.android.server.wm.ProtoLogGroup; import java.io.File; diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 57a6776ebc6c..9a30f1de70f0 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -79,7 +79,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D private final Context mContext; - private final WindowManagerService mWindowManager; private Handler mHandler = new Handler(); private NotificationDelegate mNotificationDelegate; private volatile IStatusBar mBar; @@ -93,6 +92,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D private final Object mLock = new Object(); private final DeathRecipient mDeathRecipient = new DeathRecipient(); private int mCurrentUserId; + private boolean mTracingEnabled; private SparseArray<UiState> mDisplayUiState = new SparseArray<>(); @@ -176,11 +176,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } /** - * Construct the service, add the status bar view to the window manager + * Construct the service */ - public StatusBarManagerService(Context context, WindowManagerService windowManager) { + public StatusBarManagerService(Context context) { mContext = context; - mWindowManager = windowManager; LocalServices.addService(StatusBarManagerInternal.class, mInternalService); LocalServices.addService(GlobalActionsProvider.class, mGlobalActionsProvider); @@ -720,6 +719,31 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } } + @Override + public void startTracing() { + if (mBar != null) { + try { + mBar.startTracing(); + mTracingEnabled = true; + } catch (RemoteException ex) {} + } + } + + @Override + public void stopTracing() { + if (mBar != null) { + try { + mTracingEnabled = false; + mBar.stopTracing(); + } catch (RemoteException ex) {} + } + } + + @Override + public boolean isTracing() { + return mTracingEnabled; + } + // TODO(b/117478341): make it aware of multi-display if needed. @Override public void disable(int what, IBinder token, String pkg) { diff --git a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java index d7f86cd65ae9..a79c19f7bc17 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java +++ b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java @@ -72,6 +72,8 @@ public class StatusBarShellCommand extends ShellCommand { return runDisableForSetup(); case "send-disable-flag": return runSendDisableFlag(); + case "tracing": + return runTracing(); default: return handleDefaultCommands(cmd); } @@ -185,6 +187,18 @@ public class StatusBarShellCommand extends ShellCommand { return 0; } + private int runTracing() { + switch (getNextArg()) { + case "start": + mInterface.startTracing(); + break; + case "stop": + mInterface.stopTracing(); + break; + } + return 0; + } + @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); @@ -233,6 +247,9 @@ public class StatusBarShellCommand extends ShellCommand { pw.println(" clock - disable clock appearing in status bar"); pw.println(" notification-icons - disable notification icons from status bar"); pw.println(""); + pw.println(" tracing (start | stop)"); + pw.println(" Start or stop SystemUI tracing"); + pw.println(""); } /** diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java index 0be90fcb2b84..ba3dc607f6cc 100644 --- a/services/core/java/com/android/server/wm/WindowTracing.java +++ b/services/core/java/com/android/server/wm/WindowTracing.java @@ -35,7 +35,7 @@ import android.util.proto.ProtoOutputStream; import android.view.Choreographer; import com.android.server.protolog.ProtoLogImpl; -import com.android.server.utils.TraceBuffer; +import com.android.internal.util.TraceBuffer; import java.io.File; import java.io.IOException; @@ -64,7 +64,7 @@ class WindowTracing { private final Object mEnabledLock = new Object(); private final File mTraceFile; - private final com.android.server.utils.TraceBuffer mBuffer; + private final TraceBuffer mBuffer; private final Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) -> log("onFrame" /* where */); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index df2b9e932fbc..4f5c1abae73c 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1327,7 +1327,7 @@ public final class SystemServer { if (!isWatch) { t.traceBegin("StartStatusBarManagerService"); try { - statusBar = new StatusBarManagerService(context, wm); + statusBar = new StatusBarManagerService(context); ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar); } catch (Throwable e) { reportWtf("starting StatusBarManagerService", e); diff --git a/services/tests/servicestests/src/com/android/server/utils/TraceBufferTest.java b/services/tests/servicestests/src/com/android/server/utils/TraceBufferTest.java index 09b75e71d946..0e50f2a1b6ad 100644 --- a/services/tests/servicestests/src/com/android/server/utils/TraceBufferTest.java +++ b/services/tests/servicestests/src/com/android/server/utils/TraceBufferTest.java @@ -30,6 +30,7 @@ import android.util.proto.ProtoOutputStream; import androidx.test.filters.SmallTest; import com.android.internal.util.Preconditions; +import com.android.internal.util.TraceBuffer; import org.junit.After; import org.junit.Before; |