diff options
9 files changed, 129 insertions, 34 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 new file mode 100644 index 000000000000..74fd13f9564e --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginEnabler.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.shared.plugins; + +import android.content.ComponentName; + +/** + * Enables and disables plugins. + */ +public interface PluginEnabler { + void setEnabled(ComponentName component, boolean enabled); + boolean isEnabled(ComponentName component); +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java index 985789415363..c6a086dcfbdc 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java @@ -14,6 +14,7 @@ package com.android.systemui.shared.plugins; +import android.annotation.Nullable; import android.content.Context; import android.os.Looper; @@ -26,9 +27,10 @@ public interface PluginInitializer { /** * This Runnable is run on the bg looper during initialization of {@link PluginManagerImpl}. - * It can be null. */ - Runnable getBgInitCallback(); + @Nullable Runnable getBgInitCallback(); String[] getWhitelistedPlugins(Context context); + + PluginEnabler getPluginEnabler(Context context); } 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 e80c079f60de..8cc6091f52f5 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 @@ -159,10 +159,8 @@ public class PluginInstanceManager<T extends Plugin> { // plugin, if the plugin causing a crash cannot be identified, they are all disabled // assuming one of them must be bad. Log.w(TAG, "Disabling plugin " + info.mPackage + "/" + info.mClass); - mPm.setComponentEnabledSetting( - new ComponentName(info.mPackage, info.mClass), - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); + mManager.getPluginEnabler().setEnabled(new ComponentName(info.mPackage, info.mClass), + false); } public <T> boolean dependsOn(Plugin p, Class<T> cls) { @@ -280,8 +278,7 @@ public class PluginInstanceManager<T extends Plugin> { if (pkgName != null) { intent.setPackage(pkgName); } - List<ResolveInfo> result = - mPm.queryIntentServices(intent, 0); + List<ResolveInfo> result = mPm.queryIntentServices(intent, 0); if (DEBUG) Log.d(TAG, "Found " + result.size() + " plugins"); if (result.size() > 1 && !mAllowMultiple) { // TODO: Show warning. @@ -306,6 +303,10 @@ public class PluginInstanceManager<T extends Plugin> { Log.w(TAG, "Plugin cannot be loaded on production build: " + component); return null; } + if (!mManager.getPluginEnabler().isEnabled(component)) { + if (DEBUG) Log.d(TAG, "Plugin is not enabled, aborting load: " + component); + return null; + } String pkg = component.getPackageName(); String cls = component.getClassName(); try { 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 7f1d161123f2..a54e08eba23d 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 @@ -41,12 +41,11 @@ import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; - import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.annotations.ProvidesInterface; import com.android.systemui.shared.plugins.PluginInstanceManager.PluginContextWrapper; import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo; -import com.android.systemui.plugins.annotations.ProvidesInterface; import dalvik.system.PathClassLoader; @@ -74,6 +73,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage private final PluginInstanceManagerFactory mFactory; private final boolean isDebuggable; private final PluginPrefs mPluginPrefs; + private final PluginEnabler mPluginEnabler; private ClassLoaderFilter mParentClassLoader; private boolean mListening; private boolean mHasOneShot; @@ -94,6 +94,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage isDebuggable = debuggable; mWhitelistedPlugins.addAll(Arrays.asList(initializer.getWhitelistedPlugins(mContext))); mPluginPrefs = new PluginPrefs(mContext); + mPluginEnabler = initializer.getPluginEnabler(mContext); PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler( defaultHandler); @@ -109,6 +110,10 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage return mWhitelistedPlugins.toArray(new String[0]); } + public PluginEnabler getPluginEnabler() { + return mPluginEnabler; + } + public <T extends Plugin> T getOneShotPlugin(Class<T> cls) { ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class); if (info == null) { @@ -202,9 +207,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage Uri uri = intent.getData(); ComponentName component = ComponentName.unflattenFromString( uri.toString().substring(10)); - mContext.getPackageManager().setComponentEnabledSetting(component, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); + getPluginEnabler().setEnabled(component, false); mContext.getSystemService(NotificationManager.class).cancel(component.getClassName(), SystemMessage.NOTE_PLUGIN); } else { diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java new file mode 100644 index 000000000000..e2417f7b6397 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginEnablerImpl.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.plugins; + +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.shared.plugins.PluginEnabler; + +public class PluginEnablerImpl implements PluginEnabler { + + final private PackageManager mPm; + + public PluginEnablerImpl(Context context) { + this(context.getPackageManager()); + } + + @VisibleForTesting public PluginEnablerImpl(PackageManager pm) { + mPm = pm; + } + + @Override + public void setEnabled(ComponentName component, boolean enabled) { + final int desiredState = enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED + : PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + mPm.setComponentEnabledSetting(component, desiredState, PackageManager.DONT_KILL_APP); + } + + @Override + public boolean isEnabled(ComponentName component) { + return mPm.getComponentEnabledSetting(component) + != PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java index 108c2d05d76c..ac0a226080bf 100644 --- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java @@ -18,6 +18,7 @@ import android.content.Context; import android.os.Looper; import com.android.systemui.Dependency; +import com.android.systemui.shared.plugins.PluginEnabler; import com.android.systemui.shared.plugins.PluginInitializer; import com.android.systemui.R; @@ -44,4 +45,8 @@ public class PluginInitializerImpl implements PluginInitializer { public String[] getWhitelistedPlugins(Context context) { return context.getResources().getStringArray(R.array.config_pluginWhitelist); } + + public PluginEnabler getPluginEnabler(Context context) { + return new PluginEnablerImpl(context); + } } diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java index 71414a266724..0826054f3740 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java @@ -25,15 +25,13 @@ import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; -import androidx.preference.PreferenceFragment; -import androidx.preference.SwitchPreference; -import androidx.preference.PreferenceScreen; -import androidx.preference.PreferenceViewHolder; import android.util.ArrayMap; import android.util.ArraySet; import android.view.View; import com.android.systemui.R; +import com.android.systemui.plugins.PluginEnablerImpl; +import com.android.systemui.shared.plugins.PluginEnabler; import com.android.systemui.shared.plugins.PluginInstanceManager; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginPrefs; @@ -41,12 +39,18 @@ import com.android.systemui.shared.plugins.PluginPrefs; import java.util.List; import java.util.Set; +import androidx.preference.PreferenceFragment; +import androidx.preference.PreferenceScreen; +import androidx.preference.PreferenceViewHolder; +import androidx.preference.SwitchPreference; + public class PluginFragment extends PreferenceFragment { public static final String ACTION_PLUGIN_SETTINGS = "com.android.systemui.action.PLUGIN_SETTINGS"; private PluginPrefs mPluginPrefs; + private PluginEnabler mPluginEnabler; @Override public void onCreate(Bundle savedInstanceState) { @@ -68,6 +72,7 @@ public class PluginFragment extends PreferenceFragment { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + mPluginEnabler = new PluginEnablerImpl(getContext()); loadPrefs(); } @@ -98,7 +103,7 @@ public class PluginFragment extends PreferenceFragment { PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_SERVICES); apps.forEach(app -> { if (!plugins.containsKey(app.packageName)) return; - SwitchPreference pref = new PluginPreference(prefContext, app); + SwitchPreference pref = new PluginPreference(prefContext, app, mPluginEnabler); pref.setSummary("Plugins: " + toString(plugins.get(app.packageName))); screen.addPreference(pref); }); @@ -139,15 +144,16 @@ public class PluginFragment extends PreferenceFragment { private static class PluginPreference extends SwitchPreference { private final boolean mHasSettings; private final PackageInfo mInfo; - private final PackageManager mPm; + private final PluginEnabler mPluginEnabler; - public PluginPreference(Context prefContext, PackageInfo info) { + public PluginPreference(Context prefContext, PackageInfo info, PluginEnabler pluginEnabler) { super(prefContext); - mPm = prefContext.getPackageManager(); - mHasSettings = mPm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS) + PackageManager pm = prefContext.getPackageManager(); + mHasSettings = pm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS) .setPackage(info.packageName), 0) != null; mInfo = info; - setTitle(info.applicationInfo.loadLabel(mPm)); + mPluginEnabler = pluginEnabler; + setTitle(info.applicationInfo.loadLabel(pm)); setChecked(isPluginEnabled()); setWidgetLayoutResource(R.layout.tuner_widget_settings_switch); } @@ -156,8 +162,7 @@ public class PluginFragment extends PreferenceFragment { for (int i = 0; i < mInfo.services.length; i++) { ComponentName componentName = new ComponentName(mInfo.packageName, mInfo.services[i].name); - if (mPm.getComponentEnabledSetting(componentName) - == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) { + if (!mPluginEnabler.isEnabled(componentName)) { return false; } } @@ -165,17 +170,14 @@ public class PluginFragment extends PreferenceFragment { } @Override - protected boolean persistBoolean(boolean value) { - final int desiredState = value ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED - : PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + protected boolean persistBoolean(boolean isEnabled) { boolean shouldSendBroadcast = false; for (int i = 0; i < mInfo.services.length; i++) { ComponentName componentName = new ComponentName(mInfo.packageName, mInfo.services[i].name); - if (mPm.getComponentEnabledSetting(componentName) != desiredState) { - mPm.setComponentEnabledSetting(componentName, desiredState, - PackageManager.DONT_KILL_APP); + if (mPluginEnabler.isEnabled(componentName) != isEnabled) { + mPluginEnabler.setEnabled(componentName, isEnabled); 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 6d1ff8c06acf..5bf60400089b 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 @@ -28,6 +28,7 @@ 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; @@ -88,6 +89,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase { mMockManager = mock(PluginManagerImpl.class); when(mMockManager.getClassLoader(any(), any())) .thenReturn(getClass().getClassLoader()); + when(mMockManager.getPluginEnabler()).thenReturn(new PluginEnablerImpl(mMockPm)); mMockVersionInfo = mock(VersionInfo.class); mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction", mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo, 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 3c7020569db4..ff1bc8abf5d1 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 @@ -37,6 +37,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.Plugin; +import com.android.systemui.plugins.PluginEnablerImpl; import com.android.systemui.plugins.PluginInitializerImpl; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.annotations.ProvidesInterface; @@ -62,6 +63,7 @@ public class PluginManagerTest extends SysuiTestCase { private PluginInstanceManager mMockPluginInstance; private PluginManagerImpl mPluginManager; private PluginListener mMockListener; + private PackageManager mMockPackageManager; private UncaughtExceptionHandler mRealExceptionHandler; private UncaughtExceptionHandler mMockExceptionHandler; @@ -79,12 +81,18 @@ public class PluginManagerTest extends SysuiTestCase { Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.any())) .thenReturn(mMockPluginInstance); + mMockPackageManager = mock(PackageManager.class); 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); + } }); resetExceptionHandler(); mMockListener = mock(PluginListener.class); @@ -182,9 +190,8 @@ public class PluginManagerTest extends SysuiTestCase { @Test public void testDisableIntent() { NotificationManager nm = mock(NotificationManager.class); - PackageManager pm = mock(PackageManager.class); mContext.addMockSystemService(Context.NOTIFICATION_SERVICE, nm); - mContext.setMockPackageManager(pm); + mContext.setMockPackageManager(mMockPackageManager); ComponentName testComponent = new ComponentName(getContext().getPackageName(), PluginManagerTest.class.getName()); @@ -192,7 +199,7 @@ public class PluginManagerTest extends SysuiTestCase { intent.setData(Uri.parse("package://" + testComponent.flattenToString())); mPluginManager.onReceive(mContext, intent); verify(nm).cancel(eq(testComponent.getClassName()), eq(SystemMessage.NOTE_PLUGIN)); - verify(pm).setComponentEnabledSetting(eq(testComponent), + verify(mMockPackageManager).setComponentEnabledSetting(eq(testComponent), eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), eq(PackageManager.DONT_KILL_APP)); } |