summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java30
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java13
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java63
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java22
7 files changed, 124 insertions, 57 deletions
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java
index 74fd13f9564e..01b012d1fc84 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java
@@ -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);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
index 8e7fadb5c7cb..523720d54eec 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
@@ -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) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index dc2a9bd5105b..10b5f1c64d85 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -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);
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java
index e2417f7b6397..63374150adaa 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java
@@ -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);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
index dae1472c42af..0a29e04ce20f 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
@@ -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;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
index 5cc3b3c7823b..458377017fb9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
@@ -17,6 +17,7 @@ package com.android.systemui.shared.plugins;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
+
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
@@ -26,22 +27,6 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.Plugin;
-import com.android.systemui.plugins.PluginEnablerImpl;
-import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
-import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException;
-import com.android.systemui.plugins.annotations.Requires;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
-
import android.app.Activity;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
@@ -60,6 +45,21 @@ import android.support.test.annotation.UiThreadTest;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.annotations.Requires;
+import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
+import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -79,6 +79,9 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
private PluginInstanceManager mPluginInstanceManager;
private PluginManagerImpl mMockManager;
private VersionInfo mMockVersionInfo;
+ private PluginEnabler mMockEnabler;
+ ComponentName mTestPluginComponentName =
+ new ComponentName(WHITELISTED_PACKAGE, TestPlugin.class.getName());
@Before
public void setup() throws Exception {
@@ -88,9 +91,9 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
mMockPm = mock(PackageManager.class);
mMockListener = mock(PluginListener.class);
mMockManager = mock(PluginManagerImpl.class);
- when(mMockManager.getClassLoader(any(), any()))
- .thenReturn(getClass().getClassLoader());
- when(mMockManager.getPluginEnabler()).thenReturn(new PluginEnablerImpl(mMockPm));
+ when(mMockManager.getClassLoader(any(), any())).thenReturn(getClass().getClassLoader());
+ mMockEnabler = mock(PluginEnabler.class);
+ when(mMockManager.getPluginEnabler()).thenReturn(mMockEnabler);
mMockVersionInfo = mock(VersionInfo.class);
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
@@ -230,18 +233,13 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
// Start with an unrelated class.
boolean result = mPluginInstanceManager.checkAndDisable(Activity.class.getName());
assertFalse(result);
- verify(mMockPm, never()).setComponentEnabledSetting(
- ArgumentCaptor.forClass(ComponentName.class).capture(),
- ArgumentCaptor.forClass(int.class).capture(),
- ArgumentCaptor.forClass(int.class).capture());
+ verify(mMockEnabler, never()).setDisabled(any(ComponentName.class), anyInt());
// Now hand it a real class and make sure it disables the plugin.
result = mPluginInstanceManager.checkAndDisable(TestPlugin.class.getName());
assertTrue(result);
- verify(mMockPm).setComponentEnabledSetting(
- ArgumentCaptor.forClass(ComponentName.class).capture(),
- ArgumentCaptor.forClass(int.class).capture(),
- ArgumentCaptor.forClass(int.class).capture());
+ verify(mMockEnabler).setDisabled(
+ mTestPluginComponentName, PluginEnabler.DISABLED_FROM_EXPLICIT_CRASH);
}
@Test
@@ -250,10 +248,8 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
mPluginInstanceManager.disableAll();
- verify(mMockPm).setComponentEnabledSetting(
- ArgumentCaptor.forClass(ComponentName.class).capture(),
- ArgumentCaptor.forClass(int.class).capture(),
- ArgumentCaptor.forClass(int.class).capture());
+ verify(mMockEnabler).setDisabled(
+ mTestPluginComponentName, PluginEnabler.DISABLED_FROM_SYSTEM_CRASH);
}
@Test
@@ -275,8 +271,8 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
List<ResolveInfo> list = new ArrayList<>();
ResolveInfo info = new ResolveInfo();
info.serviceInfo = mock(ServiceInfo.class);
- info.serviceInfo.packageName = "com.android.systemui";
- info.serviceInfo.name = TestPlugin.class.getName();
+ info.serviceInfo.packageName = mTestPluginComponentName.getPackageName();
+ info.serviceInfo.name = mTestPluginComponentName.getClassName();
when(info.serviceInfo.loadLabel(any())).thenReturn("Test Plugin");
list.add(info);
when(mMockPm.queryIntentServices(any(), Mockito.anyInt())).thenReturn(list);
@@ -288,6 +284,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
ApplicationInfo appInfo = getContext().getApplicationInfo();
when(mMockPm.getApplicationInfo(Mockito.anyString(), Mockito.anyInt())).thenReturn(
appInfo);
+ when(mMockEnabler.isEnabled(mTestPluginComponentName)).thenReturn(true);
}
private void createPlugin() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
index ff1bc8abf5d1..76e68f1df724 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
@@ -27,7 +27,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
-import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -82,17 +81,18 @@ public class PluginManagerTest extends SysuiTestCase {
.thenReturn(mMockPluginInstance);
mMockPackageManager = mock(PackageManager.class);
- mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, true,
+ mPluginManager = new PluginManagerImpl(
+ getContext(), mMockFactory, true,
mMockExceptionHandler, new PluginInitializerImpl() {
- @Override
- public String[] getWhitelistedPlugins(Context context) {
- return new String[0];
- }
-
- @Override
- public PluginEnabler getPluginEnabler(Context context) {
- return new PluginEnablerImpl(mMockPackageManager);
- }
+ @Override
+ public String[] getWhitelistedPlugins(Context context) {
+ return new String[0];
+ }
+
+ @Override
+ public PluginEnabler getPluginEnabler(Context context) {
+ return new PluginEnablerImpl(context, mMockPackageManager);
+ }
});
resetExceptionHandler();
mMockListener = mock(PluginListener.class);