Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0a3c51b0 authored by Pablo Gamito's avatar Pablo Gamito Committed by Android (Google) Code Review
Browse files

Merge changes from topic "no-processing-protolog" into main

* changes:
  Handle null object params
  Handle potentially null strings passed as ProtoLog parameter
  Refactor
  Collect the stacktrace before entering the background thread
  Ensure we wait for all messages to be traced before terminating the trace
  Update ProtoLog tests
  Remove expensive trace call in ProtoLog log call
  Use registerGroups API
  Initialize ProtoLog instances statically
  Add register groups API
  Add logcat only ProtoLog impl
  Handle null args list
  Always remove message string argument from processed calls
  Clearly distinguish ProtoLog hash vs message interface
  Improve performance of computing if a group is enabled
  Add support for ProtoLogging without any source code pre-processing
parents 248b330d f807ee9b
Loading
Loading
Loading
Loading
+23 −12
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

@@ -65,7 +66,7 @@ public class LegacyProtoLogImpl implements IProtoLog {
    private final String mLegacyViewerConfigFilename;
    private final TraceBuffer mBuffer;
    private final LegacyProtoLogViewerConfigReader mViewerConfig;
    private final TreeMap<String, IProtoLogGroup> mLogGroups;
    private final Map<String, IProtoLogGroup> mLogGroups = new TreeMap<>();
    private final Runnable mCacheUpdater;
    private final int mPerChunkSize;

@@ -74,20 +75,19 @@ public class LegacyProtoLogImpl implements IProtoLog {
    private final Object mProtoLogEnabledLock = new Object();

    public LegacyProtoLogImpl(String outputFile, String viewerConfigFilename,
            TreeMap<String, IProtoLogGroup> logGroups, Runnable cacheUpdater) {
            Runnable cacheUpdater) {
        this(new File(outputFile), viewerConfigFilename, BUFFER_CAPACITY,
                new LegacyProtoLogViewerConfigReader(), PER_CHUNK_SIZE, logGroups, cacheUpdater);
                new LegacyProtoLogViewerConfigReader(), PER_CHUNK_SIZE, cacheUpdater);
    }

    public LegacyProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
            LegacyProtoLogViewerConfigReader viewerConfig, int perChunkSize,
            TreeMap<String, IProtoLogGroup> logGroups, Runnable cacheUpdater) {
            Runnable cacheUpdater) {
        mLogFile = file;
        mBuffer = new TraceBuffer(bufferCapacity);
        mLegacyViewerConfigFilename = viewerConfigFilename;
        mViewerConfig = viewerConfig;
        mPerChunkSize = perChunkSize;
        mLogGroups = logGroups;
        mCacheUpdater = cacheUpdater;
    }

@@ -97,21 +97,25 @@ public class LegacyProtoLogImpl implements IProtoLog {
    @VisibleForTesting
    @Override
    public void log(LogLevel level, IProtoLogGroup group, long messageHash, int paramsMask,
            @Nullable String messageString, Object[] args) {
            Object[] args) {
        if (group.isLogToProto()) {
            logToProto(messageHash, paramsMask, args);
        }
        if (group.isLogToLogcat()) {
            logToLogcat(group.getTag(), level, messageHash, messageString, args);
            logToLogcat(group.getTag(), level, messageHash, args);
        }
    }

    private void logToLogcat(String tag, LogLevel level, long messageHash,
            @Nullable String messageString, Object[] args) {
        String message = null;
        if (messageString == null) {
            messageString = mViewerConfig.getViewerString(messageHash);
    @Override
    public void log(LogLevel logLevel, IProtoLogGroup group, String messageString, Object... args) {
        // This will be removed very soon so no point implementing it here.
        throw new IllegalStateException(
                "Not implemented. Only implemented for PerfettoProtoLogImpl.");
    }

    private void logToLogcat(String tag, LogLevel level, long messageHash, Object[] args) {
        String message = null;
        final String messageString = mViewerConfig.getViewerString(messageHash);
        if (messageString != null) {
            if (args != null) {
                try {
@@ -410,5 +414,12 @@ public class LegacyProtoLogImpl implements IProtoLog {
        // so we ignore the level argument to this function.
        return group.isLogToLogcat() || (group.isLogToProto() && isProtoEnabled());
    }

    @Override
    public void registerGroups(IProtoLogGroup... protoLogGroups) {
        for (IProtoLogGroup group : protoLogGroups) {
            mLogGroups.put(group.name(), group);
        }
    }
}
+80 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 android.text.TextUtils;
import android.util.Log;

import com.android.internal.protolog.common.ILogger;
import com.android.internal.protolog.common.IProtoLog;
import com.android.internal.protolog.common.IProtoLogGroup;
import com.android.internal.protolog.common.LogLevel;

/**
 * Class only create and used to server temporarily for when there is source code pre-processing by
 * the ProtoLog tool, when the tracing to Perfetto flag is off, and the static REQUIRE_PROTOLOGTOOL
 * boolean is false. In which case we simply want to log protolog message to logcat. Note, that this
 * means that in such cases there is no real advantage of using protolog over logcat.
 *
 * @deprecated Should not be used. This is just a temporary class to support a legacy behavior.
 */
@Deprecated
public class LogcatOnlyProtoLogImpl implements IProtoLog {
    @Override
    public void log(LogLevel logLevel, IProtoLogGroup group, long messageHash, int paramsMask,
            Object[] args) {
        throw new RuntimeException("Not supported when using LogcatOnlyProtoLogImpl");
    }

    @Override
    public void log(LogLevel logLevel, IProtoLogGroup group, String messageString, Object[] args) {
        String formattedString = TextUtils.formatSimple(messageString, args);
        switch (logLevel) {
            case VERBOSE -> Log.v(group.getTag(), formattedString);
            case INFO -> Log.i(group.getTag(), formattedString);
            case DEBUG -> Log.d(group.getTag(), formattedString);
            case WARN -> Log.w(group.getTag(), formattedString);
            case ERROR -> Log.e(group.getTag(), formattedString);
            case WTF -> Log.wtf(group.getTag(), formattedString);
        }
    }

    @Override
    public boolean isProtoEnabled() {
        return false;
    }

    @Override
    public int startLoggingToLogcat(String[] groups, ILogger logger) {
        return 0;
    }

    @Override
    public int stopLoggingToLogcat(String[] groups, ILogger logger) {
        return 0;
    }

    @Override
    public boolean isEnabled(IProtoLogGroup group, LogLevel level) {
        return true;
    }

    @Override
    public void registerGroups(IProtoLogGroup... protoLogGroups) {
        // Does nothing
    }
}
+304 −105

File changed.

Preview size limit exceeded, changes collapsed.

+60 −39
Original line number Diff line number Diff line
@@ -44,21 +44,23 @@ public class ProtoLog {
// LINT.ThenChange(frameworks/base/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt)

    // Needs to be set directly otherwise the protologtool tries to transform the method call
    @Deprecated
    public static boolean REQUIRE_PROTOLOGTOOL = true;

    private static IProtoLog sProtoLogInstance;

    /**
     * DEBUG level log.
     *
     * @param group         {@code IProtoLogGroup} controlling this log call.
     * @param messageString constant format string for the logged message.
     * @param args          parameters to be used with the format string.
     *
     * NOTE: If source code is pre-processed by ProtoLogTool this is not the function call that is
     *       executed. Check generated code for actual call.
     */
    public static void d(IProtoLogGroup group, String messageString, Object... args) {
        // Stub, replaced by the ProtoLogTool.
        if (REQUIRE_PROTOLOGTOOL) {
            throw new UnsupportedOperationException(
                    "ProtoLog calls MUST be processed with ProtoLogTool");
        }
        logStringMessage(LogLevel.DEBUG, group, messageString, args);
    }

    /**
@@ -67,13 +69,12 @@ public class ProtoLog {
     * @param group         {@code IProtoLogGroup} controlling this log call.
     * @param messageString constant format string for the logged message.
     * @param args          parameters to be used with the format string.
     *
     * NOTE: If source code is pre-processed by ProtoLogTool this is not the function call that is
     *       executed. Check generated code for actual call.
     */
    public static void v(IProtoLogGroup group, String messageString, Object... args) {
        // Stub, replaced by the ProtoLogTool.
        if (REQUIRE_PROTOLOGTOOL) {
            throw new UnsupportedOperationException(
                    "ProtoLog calls MUST be processed with ProtoLogTool");
        }
        logStringMessage(LogLevel.VERBOSE, group, messageString, args);
    }

    /**
@@ -82,13 +83,12 @@ public class ProtoLog {
     * @param group         {@code IProtoLogGroup} controlling this log call.
     * @param messageString constant format string for the logged message.
     * @param args          parameters to be used with the format string.
     *
     * NOTE: If source code is pre-processed by ProtoLogTool this is not the function call that is
     *       executed. Check generated code for actual call.
     */
    public static void i(IProtoLogGroup group, String messageString, Object... args) {
        // Stub, replaced by the ProtoLogTool.
        if (REQUIRE_PROTOLOGTOOL) {
            throw new UnsupportedOperationException(
                    "ProtoLog calls MUST be processed with ProtoLogTool");
        }
        logStringMessage(LogLevel.INFO, group, messageString, args);
    }

    /**
@@ -97,13 +97,12 @@ public class ProtoLog {
     * @param group         {@code IProtoLogGroup} controlling this log call.
     * @param messageString constant format string for the logged message.
     * @param args          parameters to be used with the format string.
     *
     * NOTE: If source code is pre-processed by ProtoLogTool this is not the function call that is
     *       executed. Check generated code for actual call.
     */
    public static void w(IProtoLogGroup group, String messageString, Object... args) {
        // Stub, replaced by the ProtoLogTool.
        if (REQUIRE_PROTOLOGTOOL) {
            throw new UnsupportedOperationException(
                    "ProtoLog calls MUST be processed with ProtoLogTool");
        }
        logStringMessage(LogLevel.WARN, group, messageString, args);
    }

    /**
@@ -112,13 +111,12 @@ public class ProtoLog {
     * @param group         {@code IProtoLogGroup} controlling this log call.
     * @param messageString constant format string for the logged message.
     * @param args          parameters to be used with the format string.
     *
     * NOTE: If source code is pre-processed by ProtoLogTool this is not the function call that is
     *       executed. Check generated code for actual call.
     */
    public static void e(IProtoLogGroup group, String messageString, Object... args) {
        // Stub, replaced by the ProtoLogTool.
        if (REQUIRE_PROTOLOGTOOL) {
            throw new UnsupportedOperationException(
                    "ProtoLog calls MUST be processed with ProtoLogTool");
        }
        logStringMessage(LogLevel.ERROR, group, messageString, args);
    }

    /**
@@ -127,13 +125,12 @@ public class ProtoLog {
     * @param group         {@code IProtoLogGroup} controlling this log call.
     * @param messageString constant format string for the logged message.
     * @param args          parameters to be used with the format string.
     *
     * NOTE: If source code is pre-processed by ProtoLogTool this is not the function call that is
     *       executed. Check generated code for actual call.
     */
    public static void wtf(IProtoLogGroup group, String messageString, Object... args) {
        // Stub, replaced by the ProtoLogTool.
        if (REQUIRE_PROTOLOGTOOL) {
            throw new UnsupportedOperationException(
                    "ProtoLog calls MUST be processed with ProtoLogTool");
        }
        logStringMessage(LogLevel.WTF, group, messageString, args);
    }

    /**
@@ -142,11 +139,7 @@ public class ProtoLog {
     * @return true iff this is being logged.
     */
    public static boolean isEnabled(IProtoLogGroup group, LogLevel level) {
        if (REQUIRE_PROTOLOGTOOL) {
            throw new UnsupportedOperationException(
                    "ProtoLog calls MUST be processed with ProtoLogTool");
        }
        return false;
        return sProtoLogInstance.isEnabled(group, level);
    }

    /**
@@ -154,10 +147,38 @@ public class ProtoLog {
     * @return A singleton instance of ProtoLog.
     */
    public static IProtoLog getSingleInstance() {
        return sProtoLogInstance;
    }

    /**
     * Registers available protolog groups. A group must be registered before it can be used.
     * @param protoLogGroups The groups to register for use in protolog.
     */
    public static void registerGroups(IProtoLogGroup... protoLogGroups) {
        sProtoLogInstance.registerGroups(protoLogGroups);
    }

    private static void logStringMessage(LogLevel logLevel, IProtoLogGroup group,
            String stringMessage, Object... args) {
        if (sProtoLogInstance == null) {
            throw new IllegalStateException(
                    "Trying to use ProtoLog before it is initialized in this process.");
        }

        if (sProtoLogInstance.isEnabled(group, logLevel)) {
            sProtoLogInstance.log(logLevel, group, stringMessage, args);
        }
    }

    static {
        if (android.tracing.Flags.perfettoProtologTracing()) {
            sProtoLogInstance = new PerfettoProtoLogImpl();
        } else {
            if (REQUIRE_PROTOLOGTOOL) {
            throw new UnsupportedOperationException(
                    "ProtoLog calls MUST be processed with ProtoLogTool");
                throw new RuntimeException("REQUIRE_PROTOLOGTOOL not set to false.");
            } else {
                sProtoLogInstance = new LogcatOnlyProtoLogImpl();
            }
        }
        return null;
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.internal.protolog.common.LogLevel;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
@@ -138,6 +139,8 @@ public class ProtoLogDataSource extends DataSource<ProtoLogDataSource.Instance,
    }

    public static class IncrementalState {
        public final Set<Integer> protologGroupInterningSet = new HashSet<>();
        public final Set<Long> protologMessageInterningSet = new HashSet<>();
        public final Map<String, Integer> argumentInterningMap = new HashMap<>();
        public final Map<String, Integer> stacktraceInterningMap = new HashMap<>();
        public boolean clearReported = false;
Loading