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

Commit a4649ba3 authored by Hawkwood Glazier's avatar Hawkwood Glazier
Browse files

Skip dynamic load of known clock plugins

Bug: 279933902
Test: Checked load/unload cycles on device
Change-Id: I80b403ba8544c6aded5c766fb7dba6322a12a37a
parent a6550a83
Loading
Loading
Loading
Loading
+67 −2
Original line number Diff line number Diff line
@@ -48,6 +48,18 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

private val KEY_TIMESTAMP = "appliedTimestamp"
private val KNOWN_PLUGINS =
    mapOf<String, List<ClockMetadata>>(
        "com.android.systemui.falcon.one" to listOf(ClockMetadata("ANALOG_CLOCK_BIGNUM")),
        "com.android.systemui.falcon.two" to listOf(ClockMetadata("DIGITAL_CLOCK_CALLIGRAPHY")),
        "com.android.systemui.falcon.three" to listOf(ClockMetadata("DIGITAL_CLOCK_FLEX")),
        "com.android.systemui.falcon.four" to listOf(ClockMetadata("DIGITAL_CLOCK_GROWTH")),
        "com.android.systemui.falcon.five" to listOf(ClockMetadata("DIGITAL_CLOCK_HANDWRITTEN")),
        "com.android.systemui.falcon.six" to listOf(ClockMetadata("DIGITAL_CLOCK_INFLATE")),
        "com.android.systemui.falcon.seven" to listOf(ClockMetadata("DIGITAL_CLOCK_METRO")),
        "com.android.systemui.falcon.eight" to listOf(ClockMetadata("DIGITAL_CLOCK_NUMBEROVERLAP")),
        "com.android.systemui.falcon.nine" to listOf(ClockMetadata("DIGITAL_CLOCK_WEATHER")),
    )

private fun <TKey, TVal> ConcurrentHashMap<TKey, TVal>.concurrentGetOrPut(
    key: TKey,
@@ -127,8 +139,61 @@ open class ClockRegistry(

    private val pluginListener =
        object : PluginListener<ClockProviderPlugin> {
            override fun onPluginAttached(manager: PluginLifecycleManager<ClockProviderPlugin>) {
                manager.loadPlugin()
            override fun onPluginAttached(
                manager: PluginLifecycleManager<ClockProviderPlugin>
            ): Boolean {
                if (keepAllLoaded) {
                    // Always load new plugins if requested
                    return true
                }

                val knownClocks = KNOWN_PLUGINS.get(manager.getPackage())
                if (knownClocks == null) {
                    logBuffer.tryLog(
                        TAG,
                        LogLevel.WARNING,
                        { str1 = manager.getPackage() },
                        { "Loading unrecognized clock package: $str1" }
                    )
                    return true
                }

                logBuffer.tryLog(
                    TAG,
                    LogLevel.INFO,
                    { str1 = manager.getPackage() },
                    { "Skipping initial load of known clock package package: $str1" }
                )

                var isClockListChanged = false
                for (metadata in knownClocks) {
                    val id = metadata.clockId
                    val info =
                        availableClocks.concurrentGetOrPut(id, ClockInfo(metadata, null, manager)) {
                            isClockListChanged = true
                            onConnected(id)
                        }

                    if (manager != info.manager) {
                        logBuffer.tryLog(
                            TAG,
                            LogLevel.ERROR,
                            { str1 = id },
                            { "Clock Id conflict on known attach: $str1 is double registered" }
                        )
                        continue
                    }

                    info.provider = null
                }

                if (isClockListChanged) {
                    triggerOnAvailableClocksChanged()
                }
                verifyLoadedProviders()

                // Load executed via verifyLoadedProviders
                return false
            }

            override fun onPluginLoaded(
+3 −1
Original line number Diff line number Diff line
@@ -190,7 +190,9 @@ enum class ClockTickRate(val value: Int) {
data class ClockMetadata(
    val clockId: ClockId,
    val name: String,
)
) {
    constructor(clockId: ClockId) : this(clockId, clockId) {}
}

/** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */
data class ClockConfig(
+8 −0
Original line number Diff line number Diff line
@@ -16,12 +16,20 @@

package com.android.systemui.plugins;

import android.content.ComponentName;

/**
 * Provides the ability for consumers to control plugin lifecycle.
 *
 * @param <T> is the target plugin type
 */
public interface PluginLifecycleManager<T extends Plugin> {
    /** Returns the ComponentName of the target plugin. Maybe be called when not loaded. */
    ComponentName getComponentName();

    /** Returns the package name of the target plugin. May be called when not loaded. */
    String getPackage();

    /** Returns the currently loaded plugin instance (if plugin is loaded) */
    T getPlugin();

+10 −5
Original line number Diff line number Diff line
@@ -60,13 +60,18 @@ public interface PluginListener<T extends Plugin> {

    /**
     * Called when the plugin is first attached to the host application. {@link #onPluginLoaded}
     * will be automatically called as well when first attached. This may be called multiple times
     * if multiple plugins are allowed. It may also be called in the future if the plugin package
     * changes and needs to be reloaded. Each call to {@link #onPluginAttached} will provide a new
     * or different {@link PluginLifecycleManager}.
     * will be automatically called as well when first attached if true is returned. This may be
     * called multiple times if multiple plugins are allowed. It may also be called in the future
     * if the plugin package changes and needs to be reloaded. Each call to
     * {@link #onPluginAttached} will provide a new or different {@link PluginLifecycleManager}.
     *
     * @return returning true will immediately load the plugin and call onPluginLoaded with the
     *   created object. false will skip loading, but the listener can load it at any time using the
     *   provided PluginLifecycleManager. Loading plugins immediately is the default behavior.
     */
    default void onPluginAttached(PluginLifecycleManager<T> manager) {
    default boolean onPluginAttached(PluginLifecycleManager<T> manager) {
        // Optional
        return true;
    }

    /**
+22 −14
Original line number Diff line number Diff line
@@ -79,10 +79,20 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager

    /** Alerts listener and plugin that the plugin has been created. */
    public void onCreate() {
        mListener.onPluginAttached(this);
        boolean loadPlugin = mListener.onPluginAttached(this);
        if (!loadPlugin) {
            if (mPlugin != null) {
                unloadPlugin();
            }
            return;
        }

        if (mPlugin == null) {
            loadPlugin();
        } else {
            return;
        }

        mPluginFactory.checkVersion(mPlugin);
        if (!(mPlugin instanceof PluginFragment)) {
            // Only call onCreate for plugins that aren't fragments, as fragments
            // will get the onCreate as part of the fragment lifecycle.
@@ -90,7 +100,6 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager
        }
        mListener.onPluginLoaded(mPlugin, mPluginContext, this);
    }
    }

    /** Alerts listener and plugin that the plugin is being shutdown. */
    public void onDestroy() {
@@ -118,6 +127,7 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager
            return;
        }

        mPluginFactory.checkVersion(mPlugin);
        if (!(mPlugin instanceof PluginFragment)) {
            // Only call onCreate for plugins that aren't fragments, as fragments
            // will get the onCreate as part of the fragment lifecycle.
@@ -205,12 +215,8 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager
            PluginFactory<T> pluginFactory = new PluginFactory<T>(
                    context, mInstanceFactory, appInfo, componentName, mVersionChecker, pluginClass,
                    () -> getClassLoader(appInfo, mBaseClassLoader));
            // TODO: Only create the plugin before version check if we need it for
            // legacy version check.
            T instance = pluginFactory.createPlugin();
            pluginFactory.checkVersion(instance);
            return new PluginInstance<T>(
                    context, listener, componentName, pluginFactory, instance);
                    context, listener, componentName, pluginFactory, null);
        }

        private boolean isPluginPackagePrivileged(String packageName) {
@@ -332,7 +338,9 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager
                ClassLoader loader = mClassLoaderFactory.get();
                Class<T> instanceClass = (Class<T>) Class.forName(
                        mComponentName.getClassName(), true, loader);
                return (T) mInstanceFactory.create(instanceClass);
                T result = (T) mInstanceFactory.create(instanceClass);
                Log.v(TAG, "Created plugin: " + result);
                return result;
            } catch (ClassNotFoundException ex) {
                Log.e(TAG, "Failed to load plugin", ex);
            } catch (IllegalAccessException ex) {
Loading