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

Commit f727dbbd authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Remove config_systemUIServiceComponents from SystemUI.

Remove's config_systemUIServiceComponents from SystemUI's config.xml
and replaces it with a list of Dagger providers that can easily be
defined and customized in code.

This is a step to removing our reliance on reflection and hopefully
lets SystemUI clients better tailor their binary to their needs.

Various other small code tweaks are included to address startup-order
dependent issues that were discovered while writing this CL.

Some startup customization still occurs via XML - one form factor
in particular has an overlay that relies on this. It is my intent
to find a way to move off of that in the future.

Bug: 205725937
Test: manual
Change-Id: I4c207bc9487718eddc21f364e81ec760f286bf30
parent 0d5f2aed
Loading
Loading
Loading
Loading
+0 −23
Original line number Diff line number Diff line
@@ -24,29 +24,6 @@
    <string name="config_systemUIFactoryComponent" translatable="false">
        com.android.systemui.tv.TvSystemUIFactory
    </string>
    <!-- SystemUI Services: The classes of the stuff to start. -->
    <string-array name="config_systemUIServiceComponents" translatable="false">
        <item>com.android.systemui.util.NotificationChannels</item>
        <item>com.android.systemui.volume.VolumeUI</item>
        <item>com.android.systemui.privacy.television.TvOngoingPrivacyChip</item>
        <item>com.android.systemui.statusbar.tv.TvStatusBar</item>
        <item>com.android.systemui.statusbar.tv.notifications.TvNotificationPanel</item>
        <item>com.android.systemui.statusbar.tv.notifications.TvNotificationHandler</item>
        <item>com.android.systemui.statusbar.tv.VpnStatusObserver</item>
        <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
        <item>com.android.systemui.usb.StorageNotification</item>
        <item>com.android.systemui.power.PowerUI</item>
        <item>com.android.systemui.media.RingtonePlayer</item>
        <item>com.android.systemui.keyboard.KeyboardUI</item>
        <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
        <item>@string/config_systemUIVendorServiceComponent</item>
        <item>com.android.systemui.SliceBroadcastRelayHandler</item>
        <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
        <item>com.android.systemui.accessibility.WindowMagnification</item>
        <item>com.android.systemui.toast.ToastUI</item>
        <item>com.android.systemui.wmshell.WMShell</item>
        <item>com.android.systemui.media.systemsounds.HomeSoundEffectController</item>
    </string-array>

    <!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
    <integer name="recents_svelte_level">3</integer>
+0 −31
Original line number Diff line number Diff line
@@ -292,37 +292,6 @@
    <!-- SystemUIFactory component -->
    <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string>

    <!-- SystemUI Services: The classes of base stuff to start by default for all
         configurations. -->
    <string-array name="config_systemUIServiceComponents" translatable="false">
        <item>com.android.systemui.util.NotificationChannels</item>
        <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
        <item>com.android.keyguard.KeyguardBiometricLockoutLogger</item>
        <item>com.android.systemui.recents.Recents</item>
        <item>com.android.systemui.volume.VolumeUI</item>
        <item>com.android.systemui.statusbar.phone.StatusBar</item>
        <item>com.android.systemui.usb.StorageNotification</item>
        <item>com.android.systemui.power.PowerUI</item>
        <item>com.android.systemui.media.RingtonePlayer</item>
        <item>com.android.systemui.keyboard.KeyboardUI</item>
        <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
        <item>@string/config_systemUIVendorServiceComponent</item>
        <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
        <item>com.android.systemui.LatencyTester</item>
        <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
        <item>com.android.systemui.ScreenDecorations</item>
        <item>com.android.systemui.biometrics.AuthController</item>
        <item>com.android.systemui.log.SessionTracker</item>
        <item>com.android.systemui.SliceBroadcastRelayHandler</item>
        <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
        <item>com.android.systemui.theme.ThemeOverlayController</item>
        <item>com.android.systemui.accessibility.WindowMagnification</item>
        <item>com.android.systemui.accessibility.SystemActions</item>
        <item>com.android.systemui.toast.ToastUI</item>
        <item>com.android.systemui.wmshell.WMShell</item>
        <item>com.android.systemui.clipboardoverlay.ClipboardListener</item>
    </string-array>

    <!-- SystemUI Services: The classes of the additional stuff to start. Services here are
                            specified as an overlay to provide configuration-specific services that
                            supplement those listed in config_systemUIServiceComponents. -->
+93 −42
Original line number Diff line number Diff line
@@ -49,8 +49,11 @@ import com.android.systemui.util.NotificationChannels;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;

import javax.inject.Provider;

/**
 * Application class for SystemUI.
@@ -181,17 +184,16 @@ public class SystemUIApplication extends Application implements
     */

    public void startServicesIfNeeded() {
        final String[] names = SystemUIFactory.getInstance()
                .getSystemUIServiceComponents(getResources());
        final String[] additionalNames = SystemUIFactory.getInstance()
                .getAdditionalSystemUIServiceComponents(getResources());

        final ArrayList<String> serviceComponents = new ArrayList<>();
        Collections.addAll(serviceComponents, names);
        Collections.addAll(serviceComponents, additionalNames);

        startServicesIfNeeded(/* metricsPrefix= */ "StartServices",
                serviceComponents.toArray(new String[serviceComponents.size()]));
        // Sort the startables so that we get a deterministic ordering.
        // TODO: make #start idempotent and require users of CoreStartable to call it.
        Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>(
                Comparator.comparing(Class::getName));
        sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponents());
        startServicesIfNeeded(
                sortedStartables, "StartServices", additionalNames);
    }

    /**
@@ -201,16 +203,22 @@ public class SystemUIApplication extends Application implements
     * <p>This method must only be called from the main thread.</p>
     */
    void startSecondaryUserServicesIfNeeded() {
        String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponentsPerUser(
                getResources());
        startServicesIfNeeded(/* metricsPrefix= */ "StartSecondaryServices", names);
    }

    private void startServicesIfNeeded(String metricsPrefix, String[] services) {
        // Sort the startables so that we get a deterministic ordering.
        Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>(
                Comparator.comparing(Class::getName));
        sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponentsPerUser());
        startServicesIfNeeded(
                sortedStartables, "StartSecondaryServices", new String[]{});
    }

    private void startServicesIfNeeded(
            Map<Class<?>, Provider<CoreStartable>> startables,
            String metricsPrefix,
            String[] services) {
        if (mServicesStarted) {
            return;
        }
        mServices = new CoreStartable[services.length];
        mServices = new CoreStartable[startables.size() + services.length];

        if (!mBootCompleteCache.isBootComplete()) {
            // check to see if maybe it was already completed long before we began
@@ -230,19 +238,68 @@ public class SystemUIApplication extends Application implements
        TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
                Trace.TRACE_TAG_APP);
        log.traceBegin(metricsPrefix);

        int i = 0;
        for (Map.Entry<Class<?>, Provider<CoreStartable>> entry : startables.entrySet()) {
            String clsName = entry.getKey().getName();
            int j = i;  // Copied to make lambda happy.
            timeInitialization(
                    clsName,
                    () -> mServices[j] = startStartable(clsName, entry.getValue()),
                    log,
                    metricsPrefix);
            i++;
        }

        // Loop over any "additional" startables that are defined in an xml overlay.
        final int N = services.length;
        for (int i = 0; i < N; i++) {
        for (i = 0; i < N; i++) {
            int j = i;  // Copied to make lambda happy.
            String clsName = services[i];
            if (DEBUG) Log.d(TAG, "loading: " + clsName);
            log.traceBegin(metricsPrefix + clsName);
            timeInitialization(
                    clsName,
                    () -> mServices[j + startables.size()] = startAdditionalStartable(clsName),
                    log,
                    metricsPrefix);
        }

        for (i = 0; i < mServices.length; i++) {
            if (mBootCompleteCache.isBootComplete()) {
                mServices[i].onBootCompleted();
            }

            mDumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
        }
        mSysUIComponent.getInitController().executePostInitTasks();
        log.traceEnd();

        mServicesStarted = true;
    }

    private void timeInitialization(String clsName, Runnable init, TimingsTraceLog log,
            String metricsPrefix) {
        long ti = System.currentTimeMillis();
        log.traceBegin(metricsPrefix + " " + clsName);
        init.run();
        log.traceEnd();

        // Warn if initialization of component takes too long
        ti = System.currentTimeMillis() - ti;
        if (ti > 1000) {
            Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
        }
    }

    private CoreStartable startAdditionalStartable(String clsName) {
        CoreStartable startable;
        if (DEBUG) Log.d(TAG, "loading: " + clsName);
        try {
                CoreStartable obj = mComponentHelper.resolveCoreStartable(clsName);
                if (obj == null) {
                    Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
                    obj = (CoreStartable) constructor.newInstance(this);
            startable = mComponentHelper.resolveAdditionalCoreStartable(clsName);
            if (startable == null) {
                Constructor<?> constructor = Class.forName(clsName).getConstructor(
                        Context.class);
                startable = (CoreStartable) constructor.newInstance(this);
            }
                mServices[i] = obj;
        } catch (ClassNotFoundException
                | NoSuchMethodException
                | IllegalAccessException
@@ -251,25 +308,19 @@ public class SystemUIApplication extends Application implements
            throw new RuntimeException(ex);
        }

            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
            mServices[i].start();
            log.traceEnd();

            // Warn if initialization of component takes too long
            ti = System.currentTimeMillis() - ti;
            if (ti > 1000) {
                Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
            }
            if (mBootCompleteCache.isBootComplete()) {
                mServices[i].onBootCompleted();
        return startStartable(startable);
    }

            mDumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
    private CoreStartable startStartable(String clsName, Provider<CoreStartable> provider) {
        if (DEBUG) Log.d(TAG, "loading: " + clsName);
        return startStartable(provider.get());
    }
        mSysUIComponent.getInitController().executePostInitTasks();
        log.traceEnd();

        mServicesStarted = true;
    private CoreStartable startStartable(CoreStartable startable) {
        if (DEBUG) Log.d(TAG, "running: " + startable);
        startable.start();

        return startable;
    }

    // TODO(b/217567642): add unit tests? There doesn't seem to be a SystemUiApplicationTest...
+19 −7
Original line number Diff line number Diff line
@@ -32,10 +32,14 @@ import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvid
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
import com.android.wm.shell.transition.ShellTransitions;

import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;

import javax.inject.Provider;

/**
 * Class factory to provide customizable SystemUI components.
 */
@@ -190,24 +194,32 @@ public class SystemUIFactory {
    }

    /**
     * Returns the list of system UI components that should be started.
     * Returns the list of {@link CoreStartable} components that should be started at startup.
     */
    public String[] getSystemUIServiceComponents(Resources resources) {
        return resources.getStringArray(R.array.config_systemUIServiceComponents);
    public Map<Class<?>, Provider<CoreStartable>> getStartableComponents() {
        return mSysUIComponent.getStartables();
    }

    /**
     * Returns the list of additional system UI components that should be started.
     */
    public String[] getAdditionalSystemUIServiceComponents(Resources resources) {
        return resources.getStringArray(R.array.config_additionalSystemUIServiceComponents);
        String[] results = resources.getStringArray(
                R.array.config_additionalSystemUIServiceComponents);
        String vendorComponent = resources.getString(
                R.string.config_systemUIVendorServiceComponent);

        results = Arrays.copyOf(results, results.length + 1);
        results[results.length - 1] = vendorComponent;

        return results;
    }

    /**
     * Returns the list of system UI components that should be started per user.
     * Returns the list of {@link CoreStartable} components that should be started per user.
     */
    public String[] getSystemUIServiceComponentsPerUser(Resources resources) {
        return resources.getStringArray(R.array.config_systemUIServiceComponentsPerUser);
    public Map<Class<?>, Provider<CoreStartable>> getStartableComponentsPerUser() {
        return mSysUIComponent.getPerUserStartables();
    }

    /**
+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ public interface ContextComponentHelper {
    Service resolveService(String className);

    /** Turns a classname into an instance of the class or returns null. */
    CoreStartable resolveCoreStartable(String className);
    CoreStartable resolveAdditionalCoreStartable(String className);

    /** Turns a classname into an instance of the class or returns null. */
    BroadcastReceiver resolveBroadcastReceiver(String className);
Loading