Loading packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java +3 −1 Original line number Diff line number Diff line Loading @@ -136,11 +136,12 @@ public class PluginInstanceManager<T extends Plugin> { return disableAny; } public void disableAll() { public boolean disableAll() { ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins); for (int i = 0; i < plugins.size(); i++) { disable(plugins.get(i)); } return plugins.size() != 0; } private void disable(PluginInfo info) { Loading Loading @@ -182,6 +183,7 @@ public class PluginInstanceManager<T extends Plugin> { if (DEBUG) Log.d(TAG, "onPluginConnected"); PluginPrefs.setHasPlugins(mContext); PluginInfo<T> info = (PluginInfo<T>) msg.obj; mManager.handleWtfs(); if (!(msg.obj instanceof PluginFragment)) { // Only call onDestroy for plugins that aren't fragments, as fragments // will get the onCreate as part of the fragment lifecycle. Loading packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java +25 −3 Original line number Diff line number Diff line Loading @@ -36,6 +36,9 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.Log.TerribleFailure; import android.util.Log.TerribleFailureHandler; import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -71,10 +74,11 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage private boolean mListening; private boolean mHasOneShot; private Looper mLooper; private boolean mWtfsSet; public PluginManagerImpl(Context context) { this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE, Thread.getDefaultUncaughtExceptionHandler()); Build.IS_DEBUGGABLE, Thread.getUncaughtExceptionPreHandler()); } @VisibleForTesting Loading @@ -88,7 +92,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler( defaultHandler); Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler); Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler); if (isDebuggable) { new Handler(mLooper).post(() -> { // Plugin dependencies that don't have another good home can go here, but Loading Loading @@ -290,6 +294,15 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage return false; } public void handleWtfs() { if (!mWtfsSet) { mWtfsSet = true; Log.setWtfHandler((tag, what, system) -> { throw new CrashWhilePluginActiveException(what); }); } } @VisibleForTesting public static class PluginInstanceManagerFactory { public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context, Loading Loading @@ -339,9 +352,12 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage // disable all the plugins, so we can be sure that SysUI is running as // best as possible. for (PluginInstanceManager manager : mPluginMap.values()) { manager.disableAll(); disabledAny |= manager.disableAll(); } } if (disabledAny) { throwable = new CrashWhilePluginActiveException(throwable); } // Run the normal exception handler so we can crash and cleanup our state. mHandler.uncaughtException(thread, throwable); Loading @@ -358,4 +374,10 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage return disabledAny | checkStack(throwable.getCause()); } } private class CrashWhilePluginActiveException extends RuntimeException { public CrashWhilePluginActiveException(Throwable throwable) { super(throwable); } } } packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java +3 −3 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ public class PluginManagerTest extends SysuiTestCase { public void setup() throws Exception { mDependency.injectTestDependency(Dependency.BG_LOOPER, TestableLooper.get(this).getLooper()); mRealExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); mRealExceptionHandler = Thread.getUncaughtExceptionPreHandler(); mMockExceptionHandler = mock(UncaughtExceptionHandler.class); mMockFactory = mock(PluginInstanceManagerFactory.class); mMockPluginInstance = mock(PluginInstanceManager.class); Loading Loading @@ -167,9 +167,9 @@ public class PluginManagerTest extends SysuiTestCase { } private void resetExceptionHandler() { mPluginExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); mPluginExceptionHandler = Thread.getUncaughtExceptionPreHandler(); // Set back the real exception handler so the test can crash if it wants to. Thread.setDefaultUncaughtExceptionHandler(mRealExceptionHandler); Thread.setUncaughtExceptionPreHandler(mRealExceptionHandler); } @ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION) Loading Loading
packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java +3 −1 Original line number Diff line number Diff line Loading @@ -136,11 +136,12 @@ public class PluginInstanceManager<T extends Plugin> { return disableAny; } public void disableAll() { public boolean disableAll() { ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins); for (int i = 0; i < plugins.size(); i++) { disable(plugins.get(i)); } return plugins.size() != 0; } private void disable(PluginInfo info) { Loading Loading @@ -182,6 +183,7 @@ public class PluginInstanceManager<T extends Plugin> { if (DEBUG) Log.d(TAG, "onPluginConnected"); PluginPrefs.setHasPlugins(mContext); PluginInfo<T> info = (PluginInfo<T>) msg.obj; mManager.handleWtfs(); if (!(msg.obj instanceof PluginFragment)) { // Only call onDestroy for plugins that aren't fragments, as fragments // will get the onCreate as part of the fragment lifecycle. Loading
packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java +25 −3 Original line number Diff line number Diff line Loading @@ -36,6 +36,9 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.Log.TerribleFailure; import android.util.Log.TerribleFailureHandler; import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -71,10 +74,11 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage private boolean mListening; private boolean mHasOneShot; private Looper mLooper; private boolean mWtfsSet; public PluginManagerImpl(Context context) { this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE, Thread.getDefaultUncaughtExceptionHandler()); Build.IS_DEBUGGABLE, Thread.getUncaughtExceptionPreHandler()); } @VisibleForTesting Loading @@ -88,7 +92,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler( defaultHandler); Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler); Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler); if (isDebuggable) { new Handler(mLooper).post(() -> { // Plugin dependencies that don't have another good home can go here, but Loading Loading @@ -290,6 +294,15 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage return false; } public void handleWtfs() { if (!mWtfsSet) { mWtfsSet = true; Log.setWtfHandler((tag, what, system) -> { throw new CrashWhilePluginActiveException(what); }); } } @VisibleForTesting public static class PluginInstanceManagerFactory { public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context, Loading Loading @@ -339,9 +352,12 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage // disable all the plugins, so we can be sure that SysUI is running as // best as possible. for (PluginInstanceManager manager : mPluginMap.values()) { manager.disableAll(); disabledAny |= manager.disableAll(); } } if (disabledAny) { throwable = new CrashWhilePluginActiveException(throwable); } // Run the normal exception handler so we can crash and cleanup our state. mHandler.uncaughtException(thread, throwable); Loading @@ -358,4 +374,10 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage return disabledAny | checkStack(throwable.getCause()); } } private class CrashWhilePluginActiveException extends RuntimeException { public CrashWhilePluginActiveException(Throwable throwable) { super(throwable); } } }
packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java +3 −3 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ public class PluginManagerTest extends SysuiTestCase { public void setup() throws Exception { mDependency.injectTestDependency(Dependency.BG_LOOPER, TestableLooper.get(this).getLooper()); mRealExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); mRealExceptionHandler = Thread.getUncaughtExceptionPreHandler(); mMockExceptionHandler = mock(UncaughtExceptionHandler.class); mMockFactory = mock(PluginInstanceManagerFactory.class); mMockPluginInstance = mock(PluginInstanceManager.class); Loading Loading @@ -167,9 +167,9 @@ public class PluginManagerTest extends SysuiTestCase { } private void resetExceptionHandler() { mPluginExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); mPluginExceptionHandler = Thread.getUncaughtExceptionPreHandler(); // Set back the real exception handler so the test can crash if it wants to. Thread.setDefaultUncaughtExceptionHandler(mRealExceptionHandler); Thread.setUncaughtExceptionPreHandler(mRealExceptionHandler); } @ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION) Loading