diff options
| author | 2020-08-25 22:00:02 +0000 | |
|---|---|---|
| committer | 2020-08-25 22:00:02 +0000 | |
| commit | 23b1690987643e3bf9a57a975193ab19d2949969 (patch) | |
| tree | 905bfe34c58dc1531e3d48d88e23bf0e6113cdd7 | |
| parent | 05cd7ff50a807efb182bfa28be7d6e07612cf4d9 (diff) | |
| parent | b754f5281babccc4c1e70a4474e5eacefe07f77d (diff) | |
Merge "Add some protologs for window organizers & shell"
16 files changed, 1025 insertions, 421 deletions
diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java new file mode 100644 index 000000000000..8a4eb4a9ca71 --- /dev/null +++ b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2020 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.internal.protolog; + +import static com.android.internal.protolog.ProtoLogFileProto.LOG; +import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER; +import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_H; +import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_L; +import static com.android.internal.protolog.ProtoLogFileProto.REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS; +import static com.android.internal.protolog.ProtoLogFileProto.VERSION; +import static com.android.internal.protolog.ProtoLogMessage.BOOLEAN_PARAMS; +import static com.android.internal.protolog.ProtoLogMessage.DOUBLE_PARAMS; +import static com.android.internal.protolog.ProtoLogMessage.ELAPSED_REALTIME_NANOS; +import static com.android.internal.protolog.ProtoLogMessage.MESSAGE_HASH; +import static com.android.internal.protolog.ProtoLogMessage.SINT64_PARAMS; +import static com.android.internal.protolog.ProtoLogMessage.STR_PARAMS; + +import android.annotation.Nullable; +import android.os.ShellCommand; +import android.os.SystemClock; +import android.util.Slog; +import android.util.proto.ProtoOutputStream; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.IProtoLogGroup; +import com.android.internal.protolog.common.LogDataType; +import com.android.internal.util.TraceBuffer; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.IllegalFormatConversionException; +import java.util.TreeMap; +import java.util.stream.Collectors; + + +/** + * A service for the ProtoLog logging system. + */ +public class BaseProtoLogImpl { + protected static final TreeMap<String, IProtoLogGroup> LOG_GROUPS = new TreeMap<>(); + + /** + * A runnable to update the cached output of {@link #isEnabled}. + * + * Must be invoked after every action that could change the result of {@link #isEnabled}, eg. + * starting / stopping proto log, or enabling / disabling log groups. + */ + public static Runnable sCacheUpdater = () -> { }; + + protected static void addLogGroupEnum(IProtoLogGroup[] config) { + for (IProtoLogGroup group : config) { + LOG_GROUPS.put(group.name(), group); + } + } + + private static final String TAG = "ProtoLog"; + private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L; + static final String PROTOLOG_VERSION = "1.0.0"; + + private final File mLogFile; + private final String mViewerConfigFilename; + private final TraceBuffer mBuffer; + protected final ProtoLogViewerConfigReader mViewerConfig; + + private boolean mProtoLogEnabled; + private boolean mProtoLogEnabledLockFree; + private final Object mProtoLogEnabledLock = new Object(); + + @VisibleForTesting + public enum LogLevel { + DEBUG, VERBOSE, INFO, WARN, ERROR, WTF + } + + /** + * Main log method, do not call directly. + */ + @VisibleForTesting + public void log(LogLevel level, IProtoLogGroup group, int messageHash, int paramsMask, + @Nullable String messageString, Object[] args) { + if (group.isLogToProto()) { + logToProto(messageHash, paramsMask, args); + } + if (group.isLogToLogcat()) { + logToLogcat(group.getTag(), level, messageHash, messageString, args); + } + } + + private void logToLogcat(String tag, LogLevel level, int messageHash, + @Nullable String messageString, Object[] args) { + String message = null; + if (messageString == null) { + messageString = mViewerConfig.getViewerString(messageHash); + } + if (messageString != null) { + try { + message = String.format(messageString, args); + } catch (IllegalFormatConversionException ex) { + Slog.w(TAG, "Invalid ProtoLog format string.", ex); + } + } + if (message == null) { + StringBuilder builder = new StringBuilder("UNKNOWN MESSAGE (" + messageHash + ")"); + for (Object o : args) { + builder.append(" ").append(o); + } + message = builder.toString(); + } + passToLogcat(tag, level, message); + } + + /** + * SLog wrapper. + */ + @VisibleForTesting + public void passToLogcat(String tag, LogLevel level, String message) { + switch (level) { + case DEBUG: + Slog.d(tag, message); + break; + case VERBOSE: + Slog.v(tag, message); + break; + case INFO: + Slog.i(tag, message); + break; + case WARN: + Slog.w(tag, message); + break; + case ERROR: + Slog.e(tag, message); + break; + case WTF: + Slog.wtf(tag, message); + break; + } + } + + private void logToProto(int messageHash, int paramsMask, Object[] args) { + if (!isProtoEnabled()) { + return; + } + try { + ProtoOutputStream os = new ProtoOutputStream(); + long token = os.start(LOG); + os.write(MESSAGE_HASH, messageHash); + os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos()); + + if (args != null) { + int argIndex = 0; + ArrayList<Long> longParams = new ArrayList<>(); + ArrayList<Double> doubleParams = new ArrayList<>(); + ArrayList<Boolean> booleanParams = new ArrayList<>(); + for (Object o : args) { + int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex); + try { + switch (type) { + case LogDataType.STRING: + os.write(STR_PARAMS, o.toString()); + break; + case LogDataType.LONG: + longParams.add(((Number) o).longValue()); + break; + case LogDataType.DOUBLE: + doubleParams.add(((Number) o).doubleValue()); + break; + case LogDataType.BOOLEAN: + booleanParams.add((boolean) o); + break; + } + } catch (ClassCastException ex) { + // Should not happen unless there is an error in the ProtoLogTool. + os.write(STR_PARAMS, "(INVALID PARAMS_MASK) " + o.toString()); + Slog.e(TAG, "Invalid ProtoLog paramsMask", ex); + } + argIndex++; + } + if (longParams.size() > 0) { + os.writePackedSInt64(SINT64_PARAMS, + longParams.stream().mapToLong(i -> i).toArray()); + } + if (doubleParams.size() > 0) { + os.writePackedDouble(DOUBLE_PARAMS, + doubleParams.stream().mapToDouble(i -> i).toArray()); + } + if (booleanParams.size() > 0) { + boolean[] arr = new boolean[booleanParams.size()]; + for (int i = 0; i < booleanParams.size(); i++) { + arr[i] = booleanParams.get(i); + } + os.writePackedBool(BOOLEAN_PARAMS, arr); + } + } + os.end(token); + mBuffer.add(os); + } catch (Exception e) { + Slog.e(TAG, "Exception while logging to proto", e); + } + } + + public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity, + ProtoLogViewerConfigReader viewerConfig) { + mLogFile = file; + mBuffer = new TraceBuffer(bufferCapacity); + mViewerConfigFilename = viewerConfigFilename; + mViewerConfig = viewerConfig; + } + + /** + * Starts the logging a circular proto buffer. + * + * @param pw Print writer + */ + public void startProtoLog(@Nullable PrintWriter pw) { + if (isProtoEnabled()) { + return; + } + synchronized (mProtoLogEnabledLock) { + logAndPrintln(pw, "Start logging to " + mLogFile + "."); + mBuffer.resetBuffer(); + mProtoLogEnabled = true; + mProtoLogEnabledLockFree = true; + } + sCacheUpdater.run(); + } + + /** + * Stops logging to proto. + * + * @param pw Print writer + * @param writeToFile If the current buffer should be written to disk or not + */ + public void stopProtoLog(@Nullable PrintWriter pw, boolean writeToFile) { + if (!isProtoEnabled()) { + return; + } + synchronized (mProtoLogEnabledLock) { + logAndPrintln(pw, "Stop logging to " + mLogFile + ". Waiting for log to flush."); + mProtoLogEnabled = mProtoLogEnabledLockFree = false; + if (writeToFile) { + writeProtoLogToFileLocked(); + logAndPrintln(pw, "Log written to " + mLogFile + "."); + } + if (mProtoLogEnabled) { + logAndPrintln(pw, "ERROR: logging was re-enabled while waiting for flush."); + throw new IllegalStateException("logging enabled while waiting for flush."); + } + } + sCacheUpdater.run(); + } + + /** + * Returns {@code true} iff logging to proto is enabled. + */ + public boolean isProtoEnabled() { + return mProtoLogEnabledLockFree; + } + + protected int setLogging(boolean setTextLogging, boolean value, PrintWriter pw, + String... groups) { + for (int i = 0; i < groups.length; i++) { + String group = groups[i]; + IProtoLogGroup g = LOG_GROUPS.get(group); + if (g != null) { + System.out.println("G: "+ g); + if (setTextLogging) { + g.setLogToLogcat(value); + } else { + g.setLogToProto(value); + } + } else { + logAndPrintln(pw, "No IProtoLogGroup named " + group); + return -1; + } + } + sCacheUpdater.run(); + return 0; + } + + private int unknownCommand(PrintWriter pw) { + pw.println("Unknown command"); + pw.println("Window manager logging options:"); + pw.println(" start: Start proto logging"); + pw.println(" stop: Stop proto logging"); + pw.println(" enable [group...]: Enable proto logging for given groups"); + pw.println(" disable [group...]: Disable proto logging for given groups"); + pw.println(" enable-text [group...]: Enable logcat logging for given groups"); + pw.println(" disable-text [group...]: Disable logcat logging for given groups"); + return -1; + } + + /** + * Responds to a shell command. + */ + public int onShellCommand(ShellCommand shell) { + PrintWriter pw = shell.getOutPrintWriter(); + String cmd = shell.getNextArg(); + if (cmd == null) { + return unknownCommand(pw); + } + ArrayList<String> args = new ArrayList<>(); + String arg; + while ((arg = shell.getNextArg()) != null) { + args.add(arg); + } + String[] groups = args.toArray(new String[args.size()]); + switch (cmd) { + case "start": + startProtoLog(pw); + return 0; + case "stop": + stopProtoLog(pw, true); + return 0; + case "status": + logAndPrintln(pw, getStatus()); + return 0; + case "enable": + return setLogging(false, true, pw, groups); + case "enable-text": + mViewerConfig.loadViewerConfig(pw, mViewerConfigFilename); + return setLogging(true, true, pw, groups); + case "disable": + return setLogging(false, false, pw, groups); + case "disable-text": + return setLogging(true, false, pw, groups); + default: + return unknownCommand(pw); + } + } + + /** + * Returns a human-readable ProtoLog status text. + */ + public String getStatus() { + return "ProtoLog status: " + + ((isProtoEnabled()) ? "Enabled" : "Disabled") + + "\nEnabled log groups: \n Proto: " + + LOG_GROUPS.values().stream().filter( + it -> it.isEnabled() && it.isLogToProto()) + .map(IProtoLogGroup::name).collect(Collectors.joining(" ")) + + "\n Logcat: " + + LOG_GROUPS.values().stream().filter( + it -> it.isEnabled() && it.isLogToLogcat()) + .map(IProtoLogGroup::name).collect(Collectors.joining(" ")) + + "\nLogging definitions loaded: " + mViewerConfig.knownViewerStringsNumber(); + } + + /** + * Writes the log buffer to a new file for the bugreport. + * + * This method is synchronized with {@code #startProtoLog(PrintWriter)} and + * {@link #stopProtoLog(PrintWriter, boolean)}. + */ + public void writeProtoLogToFile() { + synchronized (mProtoLogEnabledLock) { + writeProtoLogToFileLocked(); + } + } + + private void writeProtoLogToFileLocked() { + try { + long offset = + (System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() / 1000000)); + ProtoOutputStream proto = new ProtoOutputStream(); + proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE); + proto.write(VERSION, PROTOLOG_VERSION); + proto.write(REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS, offset); + mBuffer.writeTraceToFile(mLogFile, proto); + } catch (IOException e) { + Slog.e(TAG, "Unable to write buffer to file", e); + } + } + + static void logAndPrintln(@Nullable PrintWriter pw, String msg) { + Slog.i(TAG, msg); + if (pw != null) { + pw.println(msg); + pw.flush(); + } + } +} + diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java index 0834b2d87c2c..9f7436a13bdc 100644 --- a/core/java/com/android/internal/protolog/ProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java @@ -70,6 +70,8 @@ public enum ProtoLogGroup implements IProtoLogGroup { Consts.TAG_WM), WM_DEBUG_IME(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), + WM_DEBUG_WINDOW_ORGANIZER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), TEST_GROUP(true, true, false, "WindowManagetProtoLogTest"); private final boolean mEnabled; diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java index 6874f10e6abc..10224a4b9db6 100644 --- a/core/java/com/android/internal/protolog/ProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java @@ -16,58 +16,22 @@ package com.android.internal.protolog; -import static com.android.internal.protolog.ProtoLogFileProto.LOG; -import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER; -import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_H; -import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_L; -import static com.android.internal.protolog.ProtoLogFileProto.REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS; -import static com.android.internal.protolog.ProtoLogFileProto.VERSION; -import static com.android.internal.protolog.ProtoLogMessage.BOOLEAN_PARAMS; -import static com.android.internal.protolog.ProtoLogMessage.DOUBLE_PARAMS; -import static com.android.internal.protolog.ProtoLogMessage.ELAPSED_REALTIME_NANOS; -import static com.android.internal.protolog.ProtoLogMessage.MESSAGE_HASH; -import static com.android.internal.protolog.ProtoLogMessage.SINT64_PARAMS; -import static com.android.internal.protolog.ProtoLogMessage.STR_PARAMS; - import android.annotation.Nullable; -import android.os.ShellCommand; -import android.os.SystemClock; -import android.util.Slog; -import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.IProtoLogGroup; -import com.android.internal.protolog.common.LogDataType; -import com.android.internal.util.TraceBuffer; import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.IllegalFormatConversionException; -import java.util.TreeMap; -import java.util.stream.Collectors; - /** * A service for the ProtoLog logging system. */ -public class ProtoLogImpl { - private static final TreeMap<String, IProtoLogGroup> LOG_GROUPS = new TreeMap<>(); - - /** - * A runnable to update the cached output of {@link #isEnabled}. - * - * Must be invoked after every action that could change the result of {@link #isEnabled}, eg. - * starting / stopping proto log, or enabling / disabling log groups. - */ - public static Runnable sCacheUpdater = () -> { }; +public class ProtoLogImpl extends BaseProtoLogImpl { + private static final int BUFFER_CAPACITY = 1024 * 1024; + private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.pb"; + private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz"; - private static void addLogGroupEnum(IProtoLogGroup[] config) { - for (IProtoLogGroup group : config) { - LOG_GROUPS.put(group.name(), group); - } - } + private static ProtoLogImpl sServiceInstance = null; static { addLogGroupEnum(ProtoLogGroup.values()); @@ -124,30 +88,13 @@ public class ProtoLogImpl { || (group.isLogToProto() && getSingleInstance().isProtoEnabled()); } - private static final int BUFFER_CAPACITY = 1024 * 1024; - private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.pb"; - private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz"; - private static final String TAG = "ProtoLog"; - private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L; - static final String PROTOLOG_VERSION = "1.0.0"; - - private final File mLogFile; - private final TraceBuffer mBuffer; - private final ProtoLogViewerConfigReader mViewerConfig; - - private boolean mProtoLogEnabled; - private boolean mProtoLogEnabledLockFree; - private final Object mProtoLogEnabledLock = new Object(); - - private static ProtoLogImpl sServiceInstance = null; - /** * Returns the single instance of the ProtoLogImpl singleton class. */ public static synchronized ProtoLogImpl getSingleInstance() { if (sServiceInstance == null) { - sServiceInstance = new ProtoLogImpl(new File(LOG_FILENAME), BUFFER_CAPACITY, - new ProtoLogViewerConfigReader()); + sServiceInstance = new ProtoLogImpl( + new File(LOG_FILENAME), BUFFER_CAPACITY, new ProtoLogViewerConfigReader()); } return sServiceInstance; } @@ -157,307 +104,9 @@ public class ProtoLogImpl { sServiceInstance = instance; } - @VisibleForTesting - public enum LogLevel { - DEBUG, VERBOSE, INFO, WARN, ERROR, WTF - } - - /** - * Main log method, do not call directly. - */ - @VisibleForTesting - public void log(LogLevel level, IProtoLogGroup group, int messageHash, int paramsMask, - @Nullable String messageString, Object[] args) { - if (group.isLogToProto()) { - logToProto(messageHash, paramsMask, args); - } - if (group.isLogToLogcat()) { - logToLogcat(group.getTag(), level, messageHash, messageString, args); - } - } - - private void logToLogcat(String tag, LogLevel level, int messageHash, - @Nullable String messageString, Object[] args) { - String message = null; - if (messageString == null) { - messageString = mViewerConfig.getViewerString(messageHash); - } - if (messageString != null) { - try { - message = String.format(messageString, args); - } catch (IllegalFormatConversionException ex) { - Slog.w(TAG, "Invalid ProtoLog format string.", ex); - } - } - if (message == null) { - StringBuilder builder = new StringBuilder("UNKNOWN MESSAGE (" + messageHash + ")"); - for (Object o : args) { - builder.append(" ").append(o); - } - message = builder.toString(); - } - passToLogcat(tag, level, message); - } - - /** - * SLog wrapper. - */ - @VisibleForTesting - public void passToLogcat(String tag, LogLevel level, String message) { - switch (level) { - case DEBUG: - Slog.d(tag, message); - break; - case VERBOSE: - Slog.v(tag, message); - break; - case INFO: - Slog.i(tag, message); - break; - case WARN: - Slog.w(tag, message); - break; - case ERROR: - Slog.e(tag, message); - break; - case WTF: - Slog.wtf(tag, message); - break; - } - } - - private void logToProto(int messageHash, int paramsMask, Object[] args) { - if (!isProtoEnabled()) { - return; - } - try { - ProtoOutputStream os = new ProtoOutputStream(); - long token = os.start(LOG); - os.write(MESSAGE_HASH, messageHash); - os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos()); - - if (args != null) { - int argIndex = 0; - ArrayList<Long> longParams = new ArrayList<>(); - ArrayList<Double> doubleParams = new ArrayList<>(); - ArrayList<Boolean> booleanParams = new ArrayList<>(); - for (Object o : args) { - int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex); - try { - switch (type) { - case LogDataType.STRING: - os.write(STR_PARAMS, o.toString()); - break; - case LogDataType.LONG: - longParams.add(((Number) o).longValue()); - break; - case LogDataType.DOUBLE: - doubleParams.add(((Number) o).doubleValue()); - break; - case LogDataType.BOOLEAN: - booleanParams.add((boolean) o); - break; - } - } catch (ClassCastException ex) { - // Should not happen unless there is an error in the ProtoLogTool. - os.write(STR_PARAMS, "(INVALID PARAMS_MASK) " + o.toString()); - Slog.e(TAG, "Invalid ProtoLog paramsMask", ex); - } - argIndex++; - } - if (longParams.size() > 0) { - os.writePackedSInt64(SINT64_PARAMS, - longParams.stream().mapToLong(i -> i).toArray()); - } - if (doubleParams.size() > 0) { - os.writePackedDouble(DOUBLE_PARAMS, - doubleParams.stream().mapToDouble(i -> i).toArray()); - } - if (booleanParams.size() > 0) { - boolean[] arr = new boolean[booleanParams.size()]; - for (int i = 0; i < booleanParams.size(); i++) { - arr[i] = booleanParams.get(i); - } - os.writePackedBool(BOOLEAN_PARAMS, arr); - } - } - os.end(token); - mBuffer.add(os); - } catch (Exception e) { - Slog.e(TAG, "Exception while logging to proto", e); - } - } - - public ProtoLogImpl(File file, int bufferCapacity, ProtoLogViewerConfigReader viewerConfig) { - mLogFile = file; - mBuffer = new TraceBuffer(bufferCapacity); - mViewerConfig = viewerConfig; - } - - /** - * Starts the logging a circular proto buffer. - * - * @param pw Print writer - */ - public void startProtoLog(@Nullable PrintWriter pw) { - if (isProtoEnabled()) { - return; - } - synchronized (mProtoLogEnabledLock) { - logAndPrintln(pw, "Start logging to " + mLogFile + "."); - mBuffer.resetBuffer(); - mProtoLogEnabled = true; - mProtoLogEnabledLockFree = true; - } - sCacheUpdater.run(); - } - - /** - * Stops logging to proto. - * - * @param pw Print writer - * @param writeToFile If the current buffer should be written to disk or not - */ - public void stopProtoLog(@Nullable PrintWriter pw, boolean writeToFile) { - if (!isProtoEnabled()) { - return; - } - synchronized (mProtoLogEnabledLock) { - logAndPrintln(pw, "Stop logging to " + mLogFile + ". Waiting for log to flush."); - mProtoLogEnabled = mProtoLogEnabledLockFree = false; - if (writeToFile) { - writeProtoLogToFileLocked(); - logAndPrintln(pw, "Log written to " + mLogFile + "."); - } - if (mProtoLogEnabled) { - logAndPrintln(pw, "ERROR: logging was re-enabled while waiting for flush."); - throw new IllegalStateException("logging enabled while waiting for flush."); - } - } - sCacheUpdater.run(); - } - - /** - * Returns {@code true} iff logging to proto is enabled. - */ - public boolean isProtoEnabled() { - return mProtoLogEnabledLockFree; - } - - private int setLogging(ShellCommand shell, boolean setTextLogging, boolean value) { - String group; - while ((group = shell.getNextArg()) != null) { - IProtoLogGroup g = LOG_GROUPS.get(group); - if (g != null) { - if (setTextLogging) { - g.setLogToLogcat(value); - } else { - g.setLogToProto(value); - } - } else { - logAndPrintln(shell.getOutPrintWriter(), "No IProtoLogGroup named " + group); - return -1; - } - } - sCacheUpdater.run(); - return 0; - } - - private int unknownCommand(PrintWriter pw) { - pw.println("Unknown command"); - pw.println("Window manager logging options:"); - pw.println(" start: Start proto logging"); - pw.println(" stop: Stop proto logging"); - pw.println(" enable [group...]: Enable proto logging for given groups"); - pw.println(" disable [group...]: Disable proto logging for given groups"); - pw.println(" enable-text [group...]: Enable logcat logging for given groups"); - pw.println(" disable-text [group...]: Disable logcat logging for given groups"); - return -1; - } - - /** - * Responds to a shell command. - */ - public int onShellCommand(ShellCommand shell) { - PrintWriter pw = shell.getOutPrintWriter(); - String cmd = shell.getNextArg(); - if (cmd == null) { - return unknownCommand(pw); - } - switch (cmd) { - case "start": - startProtoLog(pw); - return 0; - case "stop": - stopProtoLog(pw, true); - return 0; - case "status": - logAndPrintln(pw, getStatus()); - return 0; - case "enable": - return setLogging(shell, false, true); - case "enable-text": - mViewerConfig.loadViewerConfig(pw, VIEWER_CONFIG_FILENAME); - return setLogging(shell, true, true); - case "disable": - return setLogging(shell, false, false); - case "disable-text": - return setLogging(shell, true, false); - default: - return unknownCommand(pw); - } - } - - /** - * Returns a human-readable ProtoLog status text. - */ - public String getStatus() { - return "ProtoLog status: " - + ((isProtoEnabled()) ? "Enabled" : "Disabled") - + "\nEnabled log groups: \n Proto: " - + LOG_GROUPS.values().stream().filter( - it -> it.isEnabled() && it.isLogToProto()) - .map(IProtoLogGroup::name).collect(Collectors.joining(" ")) - + "\n Logcat: " - + LOG_GROUPS.values().stream().filter( - it -> it.isEnabled() && it.isLogToLogcat()) - .map(IProtoLogGroup::name).collect(Collectors.joining(" ")) - + "\nLogging definitions loaded: " + mViewerConfig.knownViewerStringsNumber(); - } - - /** - * Writes the log buffer to a new file for the bugreport. - * - * This method is synchronized with {@code #startProtoLog(PrintWriter)} and - * {@link #stopProtoLog(PrintWriter, boolean)}. - */ - public void writeProtoLogToFile() { - synchronized (mProtoLogEnabledLock) { - writeProtoLogToFileLocked(); - } - } - - private void writeProtoLogToFileLocked() { - try { - long offset = - (System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() / 1000000)); - ProtoOutputStream proto = new ProtoOutputStream(); - proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE); - proto.write(VERSION, PROTOLOG_VERSION); - proto.write(REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS, offset); - mBuffer.writeTraceToFile(mLogFile, proto); - } catch (IOException e) { - Slog.e(TAG, "Unable to write buffer to file", e); - } - } - - - static void logAndPrintln(@Nullable PrintWriter pw, String msg) { - Slog.i(TAG, msg); - if (pw != null) { - pw.println(msg); - pw.flush(); - } + public ProtoLogImpl(File logFile, int bufferCapacity, + ProtoLogViewerConfigReader viewConfigReader) { + super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader); } } diff --git a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java index e381d30da524..aa30a7723ad9 100644 --- a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java +++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java @@ -16,6 +16,9 @@ package com.android.internal.protolog; +import android.annotation.Nullable; +import android.util.Slog; + import org.json.JSONException; import org.json.JSONObject; @@ -23,6 +26,7 @@ import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.Iterator; @@ -34,6 +38,7 @@ import java.util.zip.GZIPInputStream; * Handles loading and parsing of ProtoLog viewer configuration. */ public class ProtoLogViewerConfigReader { + private static final String TAG = "ProtoLogViewerConfigReader"; private Map<Integer, String> mLogMessageMap = null; /** Returns message format string for its hash or null if unavailable. */ @@ -49,48 +54,54 @@ public class ProtoLogViewerConfigReader { * Reads the specified viewer configuration file. Does nothing if the config is already loaded. */ public synchronized void loadViewerConfig(PrintWriter pw, String viewerConfigFilename) { - if (mLogMessageMap != null) { - return; - } try { - InputStreamReader config = new InputStreamReader( - new GZIPInputStream(new FileInputStream(viewerConfigFilename))); - BufferedReader reader = new BufferedReader(config); - StringBuilder builder = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - builder.append(line).append('\n'); - } - reader.close(); - JSONObject json = new JSONObject(builder.toString()); - JSONObject messages = json.getJSONObject("messages"); - - mLogMessageMap = new TreeMap<>(); - Iterator it = messages.keys(); - while (it.hasNext()) { - String key = (String) it.next(); - try { - int hash = Integer.parseInt(key); - JSONObject val = messages.getJSONObject(key); - String msg = val.getString("message"); - mLogMessageMap.put(hash, msg); - } catch (NumberFormatException expected) { - // Not a messageHash - skip it - } - } - ProtoLogImpl.logAndPrintln(pw, "Loaded " + mLogMessageMap.size() + loadViewerConfig(new GZIPInputStream(new FileInputStream(viewerConfigFilename))); + logAndPrintln(pw, "Loaded " + mLogMessageMap.size() + " log definitions from " + viewerConfigFilename); } catch (FileNotFoundException e) { - ProtoLogImpl.logAndPrintln(pw, "Unable to load log definitions: File " + logAndPrintln(pw, "Unable to load log definitions: File " + viewerConfigFilename + " not found." + e); } catch (IOException e) { - ProtoLogImpl.logAndPrintln(pw, - "Unable to load log definitions: IOException while reading " + logAndPrintln(pw, "Unable to load log definitions: IOException while reading " + viewerConfigFilename + ". " + e); } catch (JSONException e) { - ProtoLogImpl.logAndPrintln(pw, - "Unable to load log definitions: JSON parsing exception while reading " - + viewerConfigFilename + ". " + e); + logAndPrintln(pw, "Unable to load log definitions: JSON parsing exception while reading " + + viewerConfigFilename + ". " + e); + } + } + + /** + * Reads the specified viewer configuration input stream. + * Does nothing if the config is already loaded. + */ + public synchronized void loadViewerConfig(InputStream viewerConfigInputStream) + throws IOException, JSONException { + if (mLogMessageMap != null) { + return; + } + InputStreamReader config = new InputStreamReader(viewerConfigInputStream); + BufferedReader reader = new BufferedReader(config); + StringBuilder builder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + builder.append(line).append('\n'); + } + reader.close(); + JSONObject json = new JSONObject(builder.toString()); + JSONObject messages = json.getJSONObject("messages"); + + mLogMessageMap = new TreeMap<>(); + Iterator it = messages.keys(); + while (it.hasNext()) { + String key = (String) it.next(); + try { + int hash = Integer.parseInt(key); + JSONObject val = messages.getJSONObject(key); + String msg = val.getString("message"); + mLogMessageMap.put(hash, msg); + } catch (NumberFormatException expected) { + // Not a messageHash - skip it + } } } @@ -103,4 +114,12 @@ public class ProtoLogViewerConfigReader { } return 0; } + + static void logAndPrintln(@Nullable PrintWriter pw, String msg) { + Slog.i(TAG, msg); + if (pw != null) { + pw.println(msg); + pw.flush(); + } + } } diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 03f7be7b41f9..75eb7b64a444 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -43,6 +43,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-2049725903": { + "message": "Task back pressed on root taskId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + }, "-2039580386": { "message": "Attempted to add input method window with unknown token %s. Aborting.", "level": "WARN", @@ -85,6 +91,12 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java" }, + "-1980468143": { + "message": "DisplayArea appeared name=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" + }, "-1976930686": { "message": "Attempted to add Accessibility overlay window with bad token %s. Aborting.", "level": "WARN", @@ -103,6 +115,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-1939861963": { + "message": "Create root task displayId=%d winMode=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + }, "-1939358269": { "message": "mRecentScreenshotAnimator finish", "level": "DEBUG", @@ -127,6 +145,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-1895337367": { + "message": "Delete root task display=%d winMode=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + }, "-1884933373": { "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", "level": "INFO", @@ -187,6 +211,12 @@ "group": "WM_DEBUG_CONFIGURATION", "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, + "-1792633344": { + "message": "Register task organizer=%s uid=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + }, "-1791031393": { "message": "Ensuring correct configuration: %s", "level": "VERBOSE", @@ -421,6 +451,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-1364754753": { + "message": "Task vanished taskId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + }, "-1352076759": { "message": "Removing app token: %s", "level": "VERBOSE", @@ -643,6 +679,18 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/WindowState.java" }, + "-951939129": { + "message": "Unregister task organizer=%s uid=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + }, + "-930893991": { + "message": "Set sync ready, syncId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/WindowOrganizerController.java" + }, "-929676529": { "message": "Configuration changes for %s, allChanges=%s", "level": "VERBOSE", @@ -793,12 +841,6 @@ "group": "WM_DEBUG_FOCUS", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-714291355": { - "message": "Losing delayed focus: %s", - "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, "-694710814": { "message": "Pausing rotation during drag", "level": "DEBUG", @@ -919,6 +961,12 @@ "group": "WM_DEBUG_CONFIGURATION", "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, + "-497620140": { + "message": "Transaction ready, syncId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/WindowOrganizerController.java" + }, "-496681057": { "message": "Attempted to get remove mode of a display that does not exist: %d", "level": "WARN", @@ -1345,6 +1393,12 @@ "group": "WM_SHOW_SURFACE_ALLOC", "at": "com\/android\/server\/wm\/BlackFrame.java" }, + "174572959": { + "message": "DisplayArea info changed name=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" + }, "184362060": { "message": "screenshotTask(%d): mCanceled=%b", "level": "DEBUG", @@ -1387,6 +1441,12 @@ "group": "WM_DEBUG_KEEP_SCREEN_ON", "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, + "232317536": { + "message": "Set intercept back pressed on root=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + }, "241961619": { "message": "Adding %s to %s", "level": "VERBOSE", @@ -1405,6 +1465,12 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, + "251812577": { + "message": "Register display organizer=%s uid=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" + }, "254883724": { "message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d", "level": "WARN", @@ -1453,6 +1519,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DisplayRotation.java" }, + "302969511": { + "message": "Task info changed taskId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + }, "302992539": { "message": "addAnimation(%s)", "level": "DEBUG", @@ -1519,12 +1591,6 @@ "group": "WM_DEBUG_BOOT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "385096046": { - "message": "Delaying loss of focus...", - "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, "399841913": { "message": "SURFACE RECOVER DESTROY: %s", "level": "INFO", @@ -1573,6 +1639,12 @@ "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, + "487621047": { + "message": "DisplayArea vanished name=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" + }, "490877640": { "message": "onStackOrderChanged(): stack=%s", "level": "DEBUG", @@ -1849,6 +1921,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "906215061": { + "message": "Apply window transaction, syncId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/WindowOrganizerController.java" + }, "913494177": { "message": "removeAllWindowsIfPossible: removing win=%s", "level": "WARN", @@ -1957,6 +2035,12 @@ "group": "WM_DEBUG_SCREEN_ON", "at": "com\/android\/server\/wm\/DisplayPolicy.java" }, + "1149424314": { + "message": "Unregister display organizer=%s uid=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" + }, "1160771501": { "message": "Resize reasons for w=%s: %s surfaceResized=%b configChanged=%b dragResizingChanged=%b reportOrientationChanged=%b", "level": "VERBOSE", @@ -2443,6 +2527,12 @@ "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "1918448345": { + "message": "Task appeared taskId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + }, "1921821199": { "message": "Preserving %s until the new one is added", "level": "VERBOSE", @@ -2676,6 +2766,9 @@ "WM_DEBUG_WINDOW_MOVEMENT": { "tag": "WindowManager" }, + "WM_DEBUG_WINDOW_ORGANIZER": { + "tag": "WindowManager" + }, "WM_ERROR": { "tag": "WindowManager" }, diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index 843b17703676..307b82e69506 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -12,14 +12,88 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Begin ProtoLog +java_library { + name: "wm_shell_protolog-groups", + srcs: [ + "src/com/android/wm/shell/protolog/ShellProtoLogGroup.java", + ":protolog-common-src", + ], +} + +filegroup { + name: "wm_shell-sources", + srcs: ["src/**/*.java"], + path: "src", +} + +genrule { + name: "wm_shell_protolog_src", + srcs: [ + ":wm_shell_protolog-groups", + ":wm_shell-sources", + ], + tools: ["protologtool"], + cmd: "$(location protologtool) transform-protolog-calls " + + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " + + "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " + + "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + + "--loggroups-jar $(location :wm_shell_protolog-groups) " + + "--output-srcjar $(out) " + + "$(locations :wm_shell-sources)", + out: ["wm_shell_protolog.srcjar"], +} + +genrule { + name: "generate-wm_shell_protolog.json", + srcs: [ + ":wm_shell_protolog-groups", + ":wm_shell-sources", + ], + tools: ["protologtool"], + cmd: "$(location protologtool) generate-viewer-config " + + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + + "--loggroups-jar $(location :wm_shell_protolog-groups) " + + "--viewer-conf $(out) " + + "$(locations :wm_shell-sources)", + out: ["wm_shell_protolog.json"], +} + +filegroup { + name: "wm_shell_protolog.json", + srcs: ["res/raw/wm_shell_protolog.json"], +} + +genrule { + name: "checked-wm_shell_protolog.json", + srcs: [ + ":generate-wm_shell_protolog.json", + ":wm_shell_protolog.json", + ], + cmd: "cp $(location :generate-wm_shell_protolog.json) $(out) && " + + "{ ! (diff $(out) $(location :wm_shell_protolog.json) | grep -q '^<') || " + + "{ echo -e '\\n\\n################################################################\\n#\\n" + + "# ERROR: ProtoLog viewer config is stale. To update it, run:\\n#\\n" + + "# cp $(location :generate-wm_shell_protolog.json) " + + "$(location :wm_shell_protolog.json)\\n#\\n" + + "################################################################\\n\\n' >&2 && false; } }", + out: ["wm_shell_protolog.json"], +} +// End ProtoLog + android_library { name: "WindowManager-Shell", srcs: [ - "src/**/*.java", + ":wm_shell_protolog_src", "src/**/I*.aidl", ], resource_dirs: [ "res", ], + static_libs: [ + "protolog-lib", + ], manifest: "AndroidManifest.xml", -} +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json new file mode 100644 index 000000000000..7242793580f9 --- /dev/null +++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json @@ -0,0 +1,46 @@ +{ + "version": "1.0.0", + "messages": { + "-1340279385": { + "message": "Remove listener=%s", + "level": "VERBOSE", + "group": "WM_SHELL_TASK_ORG", + "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" + }, + "-880817403": { + "message": "Task vanished taskId=%d", + "level": "VERBOSE", + "group": "WM_SHELL_TASK_ORG", + "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" + }, + "-460572385": { + "message": "Task appeared taskId=%d", + "level": "VERBOSE", + "group": "WM_SHELL_TASK_ORG", + "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" + }, + "-242812822": { + "message": "Add listener for modes=%s listener=%s", + "level": "VERBOSE", + "group": "WM_SHELL_TASK_ORG", + "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" + }, + "157713005": { + "message": "Task info changed taskId=%d", + "level": "VERBOSE", + "group": "WM_SHELL_TASK_ORG", + "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" + }, + "980952660": { + "message": "Task root back pressed taskId=%d", + "level": "VERBOSE", + "group": "WM_SHELL_TASK_ORG", + "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" + } + }, + "groups": { + "WM_SHELL_TASK_ORG": { + "tag": "WindowManagerShell" + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index 126374829a18..ea9576a511e9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -17,17 +17,20 @@ package com.android.wm.shell; import android.app.ActivityManager.RunningTaskInfo; +import android.app.WindowConfiguration; +import android.content.Context; import android.util.Log; import android.util.Pair; import android.util.SparseArray; -import android.util.SparseIntArray; -import android.view.Surface; import android.view.SurfaceControl; import android.window.TaskOrganizer; +import com.android.internal.protolog.common.ProtoLog; +import com.android.wm.shell.protolog.ShellProtoLogGroup; +import com.android.wm.shell.protolog.ShellProtoLogImpl; + import java.util.ArrayList; -import java.util.LinkedList; -import java.util.concurrent.CopyOnWriteArrayList; +import java.util.Arrays; /** * Unified task organizer for all components in the shell. @@ -57,6 +60,8 @@ public class ShellTaskOrganizer extends TaskOrganizer { * Adds a listener for tasks in a specific windowing mode. */ public void addListener(TaskListener listener, int... windowingModes) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Add listener for modes=%s listener=%s", + Arrays.toString(windowingModes), listener); for (int winMode : windowingModes) { ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(winMode); if (listeners == null) { @@ -84,6 +89,7 @@ public class ShellTaskOrganizer extends TaskOrganizer { * Removes a registered listener. */ public void removeListener(TaskListener listener) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Remove listener=%s", listener); for (int i = 0; i < mListenersByWindowingMode.size(); i++) { mListenersByWindowingMode.valueAt(i).remove(listener); } @@ -91,6 +97,8 @@ public class ShellTaskOrganizer extends TaskOrganizer { @Override public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task appeared taskId=%d", + taskInfo.taskId); mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, leash)); ArrayList<TaskListener> listeners = mListenersByWindowingMode.get( getWindowingMode(taskInfo)); @@ -103,6 +111,8 @@ public class ShellTaskOrganizer extends TaskOrganizer { @Override public void onTaskInfoChanged(RunningTaskInfo taskInfo) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task info changed taskId=%d", + taskInfo.taskId); Pair<RunningTaskInfo, SurfaceControl> data = mTasks.get(taskInfo.taskId); int winMode = getWindowingMode(taskInfo); int prevWinMode = getWindowingMode(data.first); @@ -134,6 +144,8 @@ public class ShellTaskOrganizer extends TaskOrganizer { @Override public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task root back pressed taskId=%d", + taskInfo.taskId); ArrayList<TaskListener> listeners = mListenersByWindowingMode.get( getWindowingMode(taskInfo)); if (listeners != null) { @@ -145,6 +157,8 @@ public class ShellTaskOrganizer extends TaskOrganizer { @Override public void onTaskVanished(RunningTaskInfo taskInfo) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task vanished taskId=%d", + taskInfo.taskId); int prevWinMode = getWindowingMode(mTasks.get(taskInfo.taskId).first); mTasks.remove(taskInfo.taskId); ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(prevWinMode); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java new file mode 100644 index 000000000000..ae0975467e3f --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 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.wm.shell.protolog; + +import com.android.internal.protolog.common.IProtoLogGroup; + +/** + * Defines logging groups for ProtoLog. + * + * This file is used by the ProtoLogTool to generate optimized logging code. + */ +public enum ShellProtoLogGroup implements IProtoLogGroup { + WM_SHELL_TASK_ORG(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM_SHELL), + TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest"); + + private final boolean mEnabled; + private volatile boolean mLogToProto; + private volatile boolean mLogToLogcat; + private final String mTag; + + /** + * @param enabled set to false to exclude all log statements for this group from + * compilation, + * they will not be available in runtime. + * @param logToProto enable binary logging for the group + * @param logToLogcat enable text logging for the group + * @param tag name of the source of the logged message + */ + ShellProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) { + this.mEnabled = enabled; + this.mLogToProto = logToProto; + this.mLogToLogcat = logToLogcat; + this.mTag = tag; + } + + @Override + public boolean isEnabled() { + return mEnabled; + } + + @Override + public boolean isLogToProto() { + return mLogToProto; + } + + @Override + public boolean isLogToLogcat() { + return mLogToLogcat; + } + + @Override + public boolean isLogToAny() { + return mLogToLogcat || mLogToProto; + } + + @Override + public String getTag() { + return mTag; + } + + @Override + public void setLogToProto(boolean logToProto) { + this.mLogToProto = logToProto; + } + + @Override + public void setLogToLogcat(boolean logToLogcat) { + this.mLogToLogcat = logToLogcat; + } + + private static class Consts { + private static final String TAG_WM_SHELL = "WindowManagerShell"; + + private static final boolean ENABLE_DEBUG = true; + private static final boolean ENABLE_LOG_TO_PROTO_DEBUG = true; + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java new file mode 100644 index 000000000000..6a925e74e847 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2020 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.wm.shell.protolog; + +import android.annotation.Nullable; +import android.content.Context; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.BaseProtoLogImpl; +import com.android.internal.protolog.ProtoLogViewerConfigReader; +import com.android.internal.protolog.common.IProtoLogGroup; +import com.android.wm.shell.R; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; + +import org.json.JSONException; + + +/** + * A service for the ProtoLog logging system. + */ +public class ShellProtoLogImpl extends BaseProtoLogImpl { + private static final String TAG = "ProtoLogImpl"; + private static final int BUFFER_CAPACITY = 1024 * 1024; + // TODO: Get the right path for the proto log file when we initialize the shell components + private static final String LOG_FILENAME = new File("wm_shell_log.pb").getAbsolutePath(); + + private static ShellProtoLogImpl sServiceInstance = null; + + private final PrintWriter mSystemOutWriter; + + static { + addLogGroupEnum(ShellProtoLogGroup.values()); + } + + /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ + public static void d(IProtoLogGroup group, int messageHash, int paramsMask, + @Nullable String messageString, + Object... args) { + getSingleInstance() + .log(LogLevel.DEBUG, group, messageHash, paramsMask, messageString, args); + } + + /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ + public static void v(IProtoLogGroup group, int messageHash, int paramsMask, + @Nullable String messageString, + Object... args) { + getSingleInstance().log(LogLevel.VERBOSE, group, messageHash, paramsMask, messageString, + args); + } + + /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ + public static void i(IProtoLogGroup group, int messageHash, int paramsMask, + @Nullable String messageString, + Object... args) { + getSingleInstance().log(LogLevel.INFO, group, messageHash, paramsMask, messageString, args); + } + + /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ + public static void w(IProtoLogGroup group, int messageHash, int paramsMask, + @Nullable String messageString, + Object... args) { + getSingleInstance().log(LogLevel.WARN, group, messageHash, paramsMask, messageString, args); + } + + /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ + public static void e(IProtoLogGroup group, int messageHash, int paramsMask, + @Nullable String messageString, + Object... args) { + getSingleInstance() + .log(LogLevel.ERROR, group, messageHash, paramsMask, messageString, args); + } + + /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ + public static void wtf(IProtoLogGroup group, int messageHash, int paramsMask, + @Nullable String messageString, + Object... args) { + getSingleInstance().log(LogLevel.WTF, group, messageHash, paramsMask, messageString, args); + } + + /** Returns true iff logging is enabled for the given {@code IProtoLogGroup}. */ + public static boolean isEnabled(IProtoLogGroup group) { + return group.isLogToLogcat() + || (group.isLogToProto() && getSingleInstance().isProtoEnabled()); + } + + /** + * Returns the single instance of the ProtoLogImpl singleton class. + */ + public static synchronized ShellProtoLogImpl getSingleInstance() { + if (sServiceInstance == null) { + sServiceInstance = new ShellProtoLogImpl(); + } + return sServiceInstance; + } + + public void startTextLogging(Context context, String... groups) { + try { + mViewerConfig.loadViewerConfig( + context.getResources().openRawResource(R.raw.wm_shell_protolog)); + setLogging(true /* setTextLogging */, true, mSystemOutWriter, groups); + } catch (IOException e) { + Log.i(TAG, "Unable to load log definitions: IOException while reading " + + "wm_shell_protolog. " + e); + } catch (JSONException e) { + Log.i(TAG, "Unable to load log definitions: JSON parsing exception while reading " + + "wm_shell_protolog. " + e); + } + } + + public void stopTextLogging(String... groups) { + setLogging(true /* setTextLogging */, false, mSystemOutWriter, groups); + } + + private ShellProtoLogImpl() { + super(new File(LOG_FILENAME), null, BUFFER_CAPACITY, + new ProtoLogViewerConfigReader()); + mSystemOutWriter = new PrintWriter(System.out, true); + } +} + diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 2fbd9ba05817..0f2e25c7025b 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -174,6 +174,9 @@ android_app { kotlincflags: ["-Xjvm-default=enable"], dxflags: ["--multi-dex"], - required: ["privapp_whitelist_com.android.systemui"], + required: [ + "privapp_whitelist_com.android.systemui", + "checked-wm_shell_protolog.json", + ], } diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index df66bf5a1051..6c06b0a19844 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -41,7 +41,12 @@ public <init>(android.content.Context); } +# Keep the wm shell lib -keep class com.android.wm.shell.* +# Keep the protolog group methods that are called by the generated code +-keepclassmembers class com.android.wm.shell.protolog.ShellProtoLogGroup { + *; +} -keep class com.android.systemui.dagger.GlobalRootComponent { *; } -keep class com.android.systemui.dagger.GlobalRootComponent$SysUIComponentImpl { *; } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index 49226000e97d..e4ff1b5dcf4f 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -29,7 +29,11 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.stackdivider.SplitScreen; import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.protolog.ShellProtoLogImpl; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Arrays; import java.util.Optional; import javax.inject.Inject; @@ -108,4 +112,35 @@ public final class WMShell extends SystemUI { } }); } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + // Handle commands if provided + for (int i = 0; i < args.length; i++) { + switch (args[i]) { + case "enable-text-logging": { + String[] groups = Arrays.copyOfRange(args, i + 1, args.length); + startTextLogging(groups); + pw.println("Starting logging on groups: " + Arrays.toString(groups)); + return; + } + case "disable-text-logging": { + String[] groups = Arrays.copyOfRange(args, i + 1, args.length); + stopTextLogging(groups); + pw.println("Stopping logging on groups: " + Arrays.toString(groups)); + return; + } + } + } + + // Dump WMShell stuff here if no commands were handled + } + + private void startTextLogging(String... groups) { + ShellProtoLogImpl.getSingleInstance().startTextLogging(mContext, groups); + } + + private void stopTextLogging(String... groups) { + ShellProtoLogImpl.getSingleInstance().stopTextLogging(groups); + } } diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java index 9a397fe07f4e..01c007e381b1 100644 --- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java +++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java @@ -18,6 +18,9 @@ package com.android.server.wm; import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; + +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; + import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -25,6 +28,8 @@ import android.view.SurfaceControl; import android.window.IDisplayAreaOrganizer; import android.window.IDisplayAreaOrganizerController; +import com.android.internal.protolog.common.ProtoLog; + import java.util.HashMap; public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerController.Stub { @@ -67,9 +72,12 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl @Override public void registerOrganizer(IDisplayAreaOrganizer organizer, int feature) { enforceStackPermission("registerOrganizer()"); + final long uid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register display organizer=%s uid=%d", + organizer.asBinder(), uid); if (mOrganizersByFeatureIds.get(feature) != null) { throw new IllegalStateException( "Replacing existing organizer currently unsupported"); @@ -96,9 +104,12 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl @Override public void unregisterOrganizer(IDisplayAreaOrganizer organizer) { enforceStackPermission("unregisterTaskOrganizer()"); + final long uid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister display organizer=%s uid=%d", + organizer.asBinder(), uid); mOrganizersByFeatureIds.entrySet().removeIf( entry -> entry.getValue().asBinder() == organizer.asBinder()); @@ -113,6 +124,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl } void onDisplayAreaAppeared(IDisplayAreaOrganizer organizer, DisplayArea da) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea appeared name=%s", da.getName()); try { SurfaceControl outSurfaceControl = new SurfaceControl(da.getSurfaceControl(), "DisplayAreaOrganizerController.onDisplayAreaAppeared"); @@ -123,6 +135,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl } void onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea vanished name=%s", da.getName()); try { organizer.onDisplayAreaVanished(da.getDisplayAreaInfo()); } catch (RemoteException e) { @@ -131,6 +144,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl } void onDisplayAreaInfoChanged(IDisplayAreaOrganizer organizer, DisplayArea da) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea info changed name=%s", da.getName()); try { organizer.onDisplayAreaInfoChanged(da.getDisplayAreaInfo()); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index f8465ddc02a2..1b779c6a0cc9 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -23,6 +23,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS; import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS; @@ -43,13 +44,12 @@ import android.window.ITaskOrganizerController; import android.window.WindowContainerToken; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ArrayUtils; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -126,6 +126,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } void onTaskAppeared(Task task) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId); final boolean visible = task.isVisible(); final RunningTaskInfo taskInfo = task.getTaskInfo(); mDeferTaskOrgCallbacksConsumer.accept(() -> { @@ -147,6 +148,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { void onTaskVanished(Task task) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task vanished taskId=%d", task.mTaskId); final RunningTaskInfo taskInfo = task.getTaskInfo(); mDeferTaskOrgCallbacksConsumer.accept(() -> { try { @@ -163,6 +165,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { // by the organizer that don't receive that signal return; } + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId); mDeferTaskOrgCallbacksConsumer.accept(() -> { if (!task.isOrganized()) { // This is safe to ignore if the task is no longer organized @@ -177,6 +180,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } void onBackPressedOnTaskRoot(Task task) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task back pressed on root taskId=%d", + task.mTaskId); if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) { // Skip if the task has not yet received taskAppeared(), except for tasks created // by the organizer that don't receive that signal @@ -306,6 +311,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task organizer=%s uid=%d", + organizer.asBinder(), uid); for (int winMode : SUPPORTED_WINDOWING_MODES) { if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) { mTaskOrganizers.add(organizer); @@ -327,6 +334,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { @Override public void unregisterTaskOrganizer(ITaskOrganizer organizer) { enforceStackPermission("unregisterTaskOrganizer()"); + final int uid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -334,6 +342,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { if (state == null) { return; } + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister task organizer=%s uid=%d", + organizer.asBinder(), uid); state.unlinkDeath(); state.dispose(); } @@ -383,6 +393,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { return null; } + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create root task displayId=%d winMode=%d", + displayId, windowingMode); final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode, ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(), true /* createdByOrganizer */); @@ -407,6 +419,9 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { throw new IllegalArgumentException( "Attempt to delete task not created by organizer task=" + task); } + + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete root task display=%d winMode=%d", + task.getDisplayId(), task.getWindowingMode()); task.removeImmediately(); return true; } @@ -614,6 +629,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set intercept back pressed on root=%b", + interceptBackPressed); final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder()); if (state != null) { state.setInterceptBackPressedOnTaskRoot(interceptBackPressed); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index d25a64890337..c7cad2f76486 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; import static android.Manifest.permission.READ_FRAME_BUFFER; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED; import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG; @@ -45,6 +46,7 @@ import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledLambda; @@ -127,6 +129,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (callback != null) { syncId = startSyncWithOrganizer(callback); } + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", + syncId); mService.deferWindowLayout(); try { ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>(); @@ -427,6 +431,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @VisibleForTesting void setSyncReady(int id) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set sync ready, syncId=%d", id); mBLASTSyncEngine.setReady(id); } @@ -436,9 +441,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } @Override - public void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady) { + public void onTransactionReady(int syncId, Set<WindowContainer> windowContainersReady) { + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Transaction ready, syncId=%d", syncId); final IWindowContainerTransactionCallback callback = - mTransactionCallbacksByPendingSyncId.get(mSyncId); + mTransactionCallbacksByPendingSyncId.get(syncId); SurfaceControl.Transaction mergedTransaction = new SurfaceControl.Transaction(); for (WindowContainer container : windowContainersReady) { @@ -446,14 +452,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } try { - callback.onTransactionReady(mSyncId, mergedTransaction); + callback.onTransactionReady(syncId, mergedTransaction); } catch (RemoteException e) { // If there's an exception when trying to send the mergedTransaction to the client, we // should immediately apply it here so the transactions aren't lost. mergedTransaction.apply(); } - mTransactionCallbacksByPendingSyncId.remove(mSyncId); + mTransactionCallbacksByPendingSyncId.remove(syncId); } @Override |