Add some protologs for window organizers & shell
- Refactor out base protolog impl so that shell can have it's own
implementation which takes a different viewer config (from the resources
directly instead of a separate file in /system/etc)
- Setup the protolog transform for shell classes
- Add some basic protologs for displayarea/task organizer controller
& shell task org (for now only text logging)
Bug: 161980327
Test: adb shell wm logging enable-text WM_DEBUG_WINDOW_ORGANIZER
Test: adb shell dumpsys activity service SystemUIService WMShell enable-text-logging WM_SHELL_TASK_ORG
Test: atest ProtoLogImplTest \
ProtoLogViewerConfigReaderTest \
WmTests:ProtoLogIntegrationTest \
LogDataTypeTest \
protologtool-tests
Change-Id: I4c3fd6aaea04987c26ac56e9baf9fc8ab75a3f34
Signed-off-by: Winson Chung <winsonc@google.com>
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 0000000..8a4eb4a
--- /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 0834b2d..9f7436a 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -70,6 +70,8 @@
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 6874f10..10224a4 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<>();
+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";
- /**
- * 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 = () -> { };
-
- 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 @@
|| (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 @@
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 e381d30..aa30a77 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.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 @@
* 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 @@
* Reads the specified viewer configuration file. Does nothing if the config is already loaded.
*/
public synchronized void loadViewerConfig(PrintWriter pw, String viewerConfigFilename) {
+ try {
+ loadViewerConfig(new GZIPInputStream(new FileInputStream(viewerConfigFilename)));
+ logAndPrintln(pw, "Loaded " + mLogMessageMap.size()
+ + " log definitions from " + viewerConfigFilename);
+ } catch (FileNotFoundException e) {
+ logAndPrintln(pw, "Unable to load log definitions: File "
+ + viewerConfigFilename + " not found." + e);
+ } catch (IOException e) {
+ logAndPrintln(pw, "Unable to load log definitions: IOException while reading "
+ + viewerConfigFilename + ". " + e);
+ } catch (JSONException 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;
}
- 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");
+ 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
- }
+ 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()
- + " log definitions from " + viewerConfigFilename);
- } catch (FileNotFoundException e) {
- ProtoLogImpl.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 "
- + viewerConfigFilename + ". " + e);
- } catch (JSONException e) {
- ProtoLogImpl.logAndPrintln(pw,
- "Unable to load log definitions: JSON parsing exception while reading "
- + viewerConfigFilename + ". " + e);
}
}
@@ -103,4 +114,12 @@
}
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 03f7be7..75eb7b6 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 843b177..307b82e 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 0000000..7242793
--- /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 1263748..ea9576a 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 @@
* 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 @@
* 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 @@
@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 @@
@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 @@
@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 @@
@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 0000000..ae09754
--- /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 0000000..6a925e7
--- /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 2fbd9ba..0f2e25c 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -174,6 +174,9 @@
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 df66bf5..6c06b0a 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 4922600..e4ff1b5 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.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 @@
}
});
}
+
+ @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 9a397fe..01c007e 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 @@
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.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 @@
@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 @@
@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 @@
}
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 @@
}
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 @@
}
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 f8465dd..1b779c6 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_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.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 @@
}
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 @@
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 @@
// 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 @@
}
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 @@
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 @@
@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 @@
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 @@
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 @@
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 @@
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 d25a648..c7cad2f 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 @@
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.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 @@
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 @@
@VisibleForTesting
void setSyncReady(int id) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set sync ready, syncId=%d", id);
mBLASTSyncEngine.setReady(id);
}
@@ -436,9 +441,10 @@
}
@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 @@
}
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