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

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

Merge "Synchronize ProtoLog configuration service" into main

parents 6fced99f 37f0674c
Loading
Loading
Loading
Loading
+108 −66
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import android.util.Log;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

import java.io.FileDescriptor;
@@ -76,11 +77,18 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ

    private final ProtoLogDataSource mDataSource;

    /**
     * Lock for synchronizing access to {@link #mConfigFileCounts}, {@link #mRegisteredGroups},
     * {@link #mClientRecords}, {@link #mLogGroupToLogcatStatus}, and {@link ClientRecord#groups}.
     */
    private final Object mConfigLock = new Object();

    /**
     * Keeps track of how many of each viewer config file is currently registered.
     * Use to keep track of which viewer config files are actively being used in tracing and might
     * need to be dumped on flush.
     */
    @GuardedBy("mConfigLock")
    private final Map<String, Integer> mConfigFileCounts = new HashMap<>();

    /**
@@ -96,7 +104,10 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
        @Nullable
        public final String configFile;

        /** Mutable set of ProtoLog groups registered for this client to actively trace. */
        /**
         * Mutable set of ProtoLog groups registered for this client to actively trace.
         */
        @GuardedBy("mConfigLock")
        @NonNull
        public final Set<String> groups = new ArraySet<>();

@@ -109,18 +120,21 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
    /**
     * Keeps track of all the clients that are actively tracing.
     */
    @GuardedBy("mConfigLock")
    private final Map<IBinder, ClientRecord> mClientRecords = new HashMap<>();

    /**
     * Keeps track of all the protolog groups that have been registered by clients and are still
     * being actively traced.
     */
    @GuardedBy("mConfigLock")
    private final Set<String> mRegisteredGroups = new HashSet<>();

    /**
     * Keeps track of whether or not a given group should be logged to logcat.
     * True when logging to logcat, false otherwise.
     */
    @GuardedBy("mConfigLock")
    private final Map<String, Boolean> mLogGroupToLogcatStatus = new TreeMap<>();

    /**
@@ -177,12 +191,15 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
        final IBinder clientBinder = client.asBinder();

        final String viewerConfigFile = args.viewerConfigFile;

        synchronized (mConfigLock) {
            mClientRecords.put(clientBinder, new ClientRecord(client, viewerConfigFile));

            if (viewerConfigFile != null) {
                mConfigFileCounts.put(viewerConfigFile,
                        mConfigFileCounts.getOrDefault(viewerConfigFile, 0) + 1);
            }
        }

        registerGroups(client, args.groups, args.groupsDefaultLogcatStatus);

@@ -191,8 +208,6 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ

    /**
     * Unregister the {@param client}.
     *
     * TODO: this lacks synchronization.
     */
    @Override
    public void unregisterClient(@Nullable IProtoLogClient client) {
@@ -206,7 +221,10 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
        }

        // Retrieve the client record for cleanup.
        final ClientRecord clientRecord = mClientRecords.remove(clientBinder);
        final ClientRecord clientRecord;
        boolean dumpViewerConfig = false;
        synchronized (mConfigLock) {
            clientRecord = mClientRecords.remove(clientBinder);
            if (clientRecord == null) {
                return;
            }
@@ -215,10 +233,16 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
                final var newCount = mConfigFileCounts.get(clientRecord.configFile) - 1;
                mConfigFileCounts.put(clientRecord.configFile, newCount);

            // Dump the tracing config now if no other client is going to dump the same config file.
                if (newCount == 0) {
                mViewerConfigFileTracer.trace(mDataSource, clientRecord.configFile);
                    mConfigFileCounts.remove(clientRecord.configFile);
                    dumpViewerConfig = true;
                }
            }
        }

        // Dump the tracing config now if no other client is going to dump the same config file.
        if (dumpViewerConfig) {
            mViewerConfigFileTracer.trace(mDataSource, clientRecord.configFile);
        }
    }

@@ -237,8 +261,10 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
    @Override
    @NonNull
    public String[] getGroups() {
        synchronized (mConfigLock) {
            return mRegisteredGroups.toArray(new String[0]);
        }
    }

    /**
     * Enable logging target groups to logcat.
@@ -265,7 +291,10 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
     */
    @Override
    public boolean isLoggingToLogcat(@NonNull String group) {
        final Boolean isLoggingToLogcat = mLogGroupToLogcatStatus.get(group);
        final Boolean isLoggingToLogcat;
        synchronized (mConfigLock) {
            isLoggingToLogcat = mLogGroupToLogcatStatus.get(group);
        }

        if (isLoggingToLogcat == null) {
            throw new RuntimeException(
@@ -301,6 +330,7 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
                        + " and logcatStatuses has length " + logcatStatuses.length);
        }

        synchronized (mConfigLock) {
            final var clientRecord = mClientRecords.get(client.asBinder());
            if (clientRecord == null) {
                throw new RuntimeException("Client " + client + " is not registered");
@@ -310,26 +340,28 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
                String group = groups[i];
                boolean logcatStatus = logcatStatuses[i];

                final boolean requestedLogToLogcat;
                mRegisteredGroups.add(group);
                clientRecord.groups.add(group);

            if (!mLogGroupToLogcatStatus.containsKey(group)) {
                mLogGroupToLogcatStatus.put(group, logcatStatus);
            }
                mLogGroupToLogcatStatus.putIfAbsent(group, logcatStatus);
                requestedLogToLogcat = mLogGroupToLogcatStatus.get(group);

            boolean requestedLogToLogcat = mLogGroupToLogcatStatus.get(group);
                if (requestedLogToLogcat != logcatStatus) {
                    client.toggleLogcat(requestedLogToLogcat, new String[]{group});
                }
            }
        }
    }

    private void toggleProtoLogToLogcat(
            @NonNull PrintWriter pw, boolean enabled, @NonNull String[] groups
    ) {
        // For each client, if its groups intersect the given list, send the command to toggle.
        synchronized (mConfigLock) {
            for (var clientRecord : mClientRecords.values()) {
            final var affectedGroups = new ArraySet<>(clientRecord.groups);
                final ArraySet<String> affectedGroups;
                affectedGroups = new ArraySet<>(clientRecord.groups);
                affectedGroups.retainAll(Arrays.asList(groups));

                if (!affectedGroups.isEmpty()) {
@@ -350,7 +382,7 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ

            // Groups that actually have no clients associated indicate some kind of a bug.
            Set<String> noOpGroups = new ArraySet<>(groups);
        mClientRecords.forEach((k, v) -> noOpGroups.removeAll(v.groups));
            mClientRecords.forEach((k, r) -> noOpGroups.removeAll(r.groups));

            // Send out a warning in logcat and the PrintWriter for unrecognized groups.
            for (String group : noOpGroups) {
@@ -365,14 +397,24 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
                mLogGroupToLogcatStatus.put(group, enabled);
            }
        }
    }

    private void onTracingInstanceStart(int instanceIdx, ProtoLogDataSource.ProtoLogConfig config) {
        mRunningInstances.add(instanceIdx);
    }

    private void onTracingInstanceFlush() {
        for (String fileName : mConfigFileCounts.keySet()) {
            mViewerConfigFileTracer.trace(mDataSource, fileName);
        final var configFilesToDump = new HashSet<String>();
        synchronized (mConfigLock) {
            for (var entry : mConfigFileCounts.entrySet()) {
                if (entry.getValue() > 0) {
                    configFilesToDump.add(entry.getKey());
                }
            }
        }

        for (var configFileName : configFilesToDump) {
            mViewerConfigFileTracer.trace(mDataSource, configFileName);
        }
    }