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

Commit 865a4292 authored by Pablo Gamito's avatar Pablo Gamito
Browse files

Gracefully handle failure to connect to configuration service

It's possible that in some cases a process might not have access to the configuration service, for example isolated apps. In these cases we do not want to crash the process instead we processed to set up the ProtoLog client without connecting it to the ProtoLogConfigurationService. The caveat being that we not be able to control the logging to logcat in these processes and we might miss some decoding viewer configs

Bug: 410517697
Test: atest TracingTests
Flag: EXEMPT small change
Change-Id: Idfe22d99cf4d59055a8e5d50fc1d6c4906d2ebcb
parent bf6fdf73
Loading
Loading
Loading
Loading
+43 −19
Original line number Diff line number Diff line
@@ -135,13 +135,8 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
    protected PerfettoProtoLogImpl(
            @NonNull ProtoLogDataSource dataSource,
            @NonNull ProtoLogCacheUpdater cacheUpdater,
            @NonNull IProtoLogGroup[] groups) throws ServiceManager.ServiceNotFoundException {
        this(dataSource, cacheUpdater, groups,
                android.tracing.Flags.clientSideProtoLogging() ?
                    IProtoLogConfigurationService.Stub.asInterface(
                        ServiceManager.getServiceOrThrow(PROTOLOG_CONFIGURATION_SERVICE)
                    ) : null
        );
            @NonNull IProtoLogGroup[] groups) {
        this(dataSource, cacheUpdater, groups, getConfigurationService());
    }

    protected PerfettoProtoLogImpl(
@@ -167,8 +162,8 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
    public void enable() {
        Producer.init(InitArguments.DEFAULTS);

        if (android.tracing.Flags.clientSideProtoLogging()) {
            connectToConfigurationService();
        if (android.tracing.Flags.clientSideProtoLogging() && mConfigurationService != null) {
            connectToConfigurationServiceAsync();
        }

        mDataSource.registerOnStartCallback(this);
@@ -187,7 +182,29 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
        }
    }

    private void connectToConfigurationService() {
    @Nullable
    private static IProtoLogConfigurationService getConfigurationService() {
        if (android.tracing.Flags.clientSideProtoLogging()) {
            var service = ServiceManager.getService(PROTOLOG_CONFIGURATION_SERVICE);

            if (service != null) {
                return IProtoLogConfigurationService.Stub.asInterface(service);
            } else {
                Log.e(LOG_TAG, "Failed to get the ProtoLog Configuration Service! "
                        + "Protologging client will not be synced properly and will not be "
                        + "available for running configuration of which groups to log to logcat. "
                        + "We might also be missing viewer configs in the trace for decoding the "
                        + "messages.");
            }
        }

        // Will be null either because we are calling this before the service is ready and
        // registered with the service manager or because we are calling this from a service
        // that does not have access to the configuration service.
        return null;
    }

    private void connectToConfigurationServiceAsync() {
        Objects.requireNonNull(mConfigurationService,
                "A null ProtoLog Configuration Service was provided!");

@@ -243,7 +260,17 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
        mDataSource.unregisterOnFlushCallback(this);
        mDataSource.unregisterOnStopCallback(this);

        if (android.tracing.Flags.clientSideProtoLogging()) {
        if (android.tracing.Flags.clientSideProtoLogging() && mConfigurationService != null) {
            disconnectFromConfigurationServiceAsync();
        }

        mBackgroundThread.quitSafely();
    }

    private void disconnectFromConfigurationServiceAsync() {
        Objects.requireNonNull(mConfigurationService,
                "A null ProtoLog Configuration Service was provided!");

        mBackgroundHandler.post(() -> {
            try {
                mConfigurationService.unregisterClient(this);
@@ -253,9 +280,6 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
        });
    }

        mBackgroundThread.quitSafely();
    }

    @NonNull
    protected abstract RegisterClientArgs createConfigurationServiceRegisterClientArgs();

@@ -973,7 +997,7 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen
    }

    /**
     * This is only used by unit tests to wait until {@link #connectToConfigurationService} is
     * This is only used by unit tests to wait until {@link #connectToConfigurationServiceAsync} is
     * done. Because unit tests are sensitive to concurrent accesses.
     */
    @VisibleForTesting