Loading core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java +108 −66 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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<>(); /** Loading @@ -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<>(); Loading @@ -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<>(); /** Loading Loading @@ -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); Loading @@ -191,8 +208,6 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ /** * Unregister the {@param client}. * * TODO: this lacks synchronization. */ @Override public void unregisterClient(@Nullable IProtoLogClient client) { Loading @@ -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; } Loading @@ -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); } } Loading @@ -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. Loading @@ -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( Loading Loading @@ -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"); Loading @@ -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()) { Loading @@ -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) { Loading @@ -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); } } Loading Loading
core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java +108 −66 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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<>(); /** Loading @@ -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<>(); Loading @@ -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<>(); /** Loading Loading @@ -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); Loading @@ -191,8 +208,6 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ /** * Unregister the {@param client}. * * TODO: this lacks synchronization. */ @Override public void unregisterClient(@Nullable IProtoLogClient client) { Loading @@ -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; } Loading @@ -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); } } Loading @@ -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. Loading @@ -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( Loading Loading @@ -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"); Loading @@ -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()) { Loading @@ -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) { Loading @@ -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); } } Loading