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

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

Track when plugins are disabled due to crashes.

Bug: 120901833
Change-Id: I41e5c54d059b631befac235b1d3929200764860c
Test: atest SystemUITests
parent b3c15578
Loading
Loading
Loading
Loading
+29 −1
Original line number Diff line number Diff line
@@ -14,12 +14,40 @@

package com.android.systemui.shared.plugins;

import android.annotation.IntDef;
import android.content.ComponentName;

/**
 * Enables and disables plugins.
 */
public interface PluginEnabler {
    void setEnabled(ComponentName component, boolean enabled);

    int ENABLED = 0;
    int DISABLED_MANUALLY = 1;
    int DISABLED_INVALID_VERSION = 1;
    int DISABLED_FROM_EXPLICIT_CRASH = 2;
    int DISABLED_FROM_SYSTEM_CRASH = 3;

    @IntDef({ENABLED, DISABLED_MANUALLY, DISABLED_INVALID_VERSION, DISABLED_FROM_EXPLICIT_CRASH,
            DISABLED_FROM_SYSTEM_CRASH})
    @interface DisableReason {
    }

    /** Enables plugin via the PackageManager. */
    void setEnabled(ComponentName component);

    /** Disables a plugin via the PackageManager and records the reason for disabling. */
    void setDisabled(ComponentName component, @DisableReason int reason);

    /** Returns true if the plugin is enabled in the PackageManager. */
    boolean isEnabled(ComponentName component);

    /**
     * Returns the reason that a plugin is disabled, (if it is).
     *
     * It should return {@link #ENABLED} if the plugin is turned on.
     * It should return {@link #DISABLED_MANUALLY} if the plugin is off but the reason is unknown.
     */
    @DisableReason
    int getDisableReason(ComponentName componentName);
}
+7 −6
Original line number Diff line number Diff line
@@ -136,7 +136,7 @@ public class PluginInstanceManager<T extends Plugin> {
        ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins);
        for (PluginInfo info : plugins) {
            if (className.startsWith(info.mPackage)) {
                disable(info);
                disable(info, PluginEnabler.DISABLED_FROM_EXPLICIT_CRASH);
                disableAny = true;
            }
        }
@@ -146,12 +146,13 @@ public class PluginInstanceManager<T extends Plugin> {
    public boolean disableAll() {
        ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins);
        for (int i = 0; i < plugins.size(); i++) {
            disable(plugins.get(i));
            disable(plugins.get(i), PluginEnabler.DISABLED_FROM_SYSTEM_CRASH);
        }
        return plugins.size() != 0;
    }

    private void disable(PluginInfo info) {
    private void disable(PluginInfo info,
            @PluginEnabler.DisableReason int reason) {
        // Live by the sword, die by the sword.
        // Misbehaving plugins get disabled and won't come back until uninstall/reinstall.

@@ -162,9 +163,9 @@ public class PluginInstanceManager<T extends Plugin> {
            // Don't disable whitelisted plugins as they are a part of the OS.
            return;
        }
        Log.w(TAG, "Disabling plugin " + info.mPackage + "/" + info.mClass);
        mManager.getPluginEnabler().setEnabled(new ComponentName(info.mPackage, info.mClass),
                false);
        ComponentName pluginComponent = new ComponentName(info.mPackage, info.mClass);
        Log.w(TAG, "Disabling plugin " + pluginComponent.flattenToShortString());
        mManager.getPluginEnabler().setDisabled(pluginComponent, reason);
    }

    public <T> boolean dependsOn(Plugin p, Class<T> cls) {
+14 −1
Original line number Diff line number Diff line
@@ -184,6 +184,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
        mListening = true;
        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addAction(PLUGIN_CHANGED);
        filter.addAction(DISABLE_PLUGIN);
@@ -214,12 +215,13 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
                // Don't disable whitelisted plugins as they are a part of the OS.
                return;
            }
            getPluginEnabler().setEnabled(component, false);
            getPluginEnabler().setDisabled(component, PluginEnabler.DISABLED_INVALID_VERSION);
            mContext.getSystemService(NotificationManager.class).cancel(component.getClassName(),
                    SystemMessage.NOTE_PLUGIN);
        } else {
            Uri data = intent.getData();
            String pkg = data.getEncodedSchemeSpecificPart();
            ComponentName componentName = ComponentName.unflattenFromString(pkg);
            if (mOneShotPackages.contains(pkg)) {
                int icon = mContext.getResources().getIdentifier("tuner", "drawable",
                        mContext.getPackageName());
@@ -256,6 +258,17 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
                    Log.v(TAG, "Reloading " + pkg);
                }
            }
            if (Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())) {
                @PluginEnabler.DisableReason int disableReason =
                        getPluginEnabler().getDisableReason(componentName);
                if (disableReason == PluginEnabler.DISABLED_FROM_EXPLICIT_CRASH
                        || disableReason == PluginEnabler.DISABLED_FROM_SYSTEM_CRASH
                        || disableReason == PluginEnabler.DISABLED_INVALID_VERSION) {
                    Log.i(TAG, "Re-enabling previously disabled plugin that has been "
                            + "updated: " + componentName.flattenToShortString());
                    getPluginEnabler().setEnabled(componentName);
                }
            }
            if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
                for (PluginInstanceManager manager : mPluginMap.values()) {
                    manager.onPackageChange(pkg);
+28 −4
Original line number Diff line number Diff line
@@ -16,28 +16,44 @@ package com.android.systemui.plugins;

import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.shared.plugins.PluginEnabler;

public class PluginEnablerImpl implements PluginEnabler {
    private static final String CRASH_DISABLED_PLUGINS_PREF_FILE = "auto_disabled_plugins_prefs";

    final private PackageManager mPm;
    private PackageManager mPm;
    private final SharedPreferences mAutoDisabledPrefs;

    public PluginEnablerImpl(Context context) {
        this(context.getPackageManager());
        this(context, context.getPackageManager());
    }

    @VisibleForTesting public PluginEnablerImpl(PackageManager pm) {
    @VisibleForTesting public PluginEnablerImpl(Context context, PackageManager pm) {
        mAutoDisabledPrefs = context.getSharedPreferences(
                CRASH_DISABLED_PLUGINS_PREF_FILE, Context.MODE_PRIVATE);
        mPm = pm;
    }

    @Override
    public void setEnabled(ComponentName component, boolean enabled) {
    public void setEnabled(ComponentName component) {
        setDisabled(component, ENABLED);
    }

    @Override
    public void setDisabled(ComponentName component, @DisableReason int reason) {
        boolean enabled = reason == ENABLED;
        final int desiredState = enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
        mPm.setComponentEnabledSetting(component, desiredState, PackageManager.DONT_KILL_APP);
        if (enabled) {
            mAutoDisabledPrefs.edit().remove(component.flattenToString()).apply();
        } else {
            mAutoDisabledPrefs.edit().putInt(component.flattenToString(), reason).apply();
        }
    }

    @Override
@@ -45,4 +61,12 @@ public class PluginEnablerImpl implements PluginEnabler {
        return mPm.getComponentEnabledSetting(component)
                != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
    }

    @Override
    public @DisableReason int getDisableReason(ComponentName componentName) {
        if (isEnabled(componentName)) {
            return ENABLED;
        }
        return mAutoDisabledPrefs.getInt(componentName.flattenToString(), DISABLED_MANUALLY);
    }
}
+5 −1
Original line number Diff line number Diff line
@@ -184,7 +184,11 @@ public class PluginFragment extends PreferenceFragment {
                        mInfo.services[i].name);

                if (mPluginEnabler.isEnabled(componentName) != isEnabled) {
                    mPluginEnabler.setEnabled(componentName, isEnabled);
                    if (isEnabled) {
                        mPluginEnabler.setEnabled(componentName);
                    } else {
                        mPluginEnabler.setDisabled(componentName, PluginEnabler.DISABLED_MANUALLY);
                    }
                    shouldSendBroadcast = true;
                }
            }
Loading