From c26aa7cf406401e4e90fd8e8a3f4ad1e9284d5d5 Mon Sep 17 00:00:00 2001 From: d34d Date: Thu, 22 Jan 2015 17:48:59 -0800 Subject: Themes: Watch all app crashes for problematic themes Only watching for exceptions that occur during an apps launch may not be sufficient to catch possible bad themes causing issues. This patch monitors all app crashes and broadcasts that there was a crash if either Resources.NotFoundException or InflateException are thrown. The remaining logic is the same as when an app launch failure occurred. We also display a notification to the user so that they know why their theme was reset to the system theme. Change-Id: I0761d02587b5b81deee4a31a89f515dbc7cc5fe6 --- .../com/android/server/AppsFailureReceiver.java | 116 +++++++++++++++++++++ .../android/server/AppsLaunchFailureReceiver.java | 86 --------------- services/java/com/android/server/SystemServer.java | 6 +- 3 files changed, 119 insertions(+), 89 deletions(-) create mode 100644 services/java/com/android/server/AppsFailureReceiver.java delete mode 100644 services/java/com/android/server/AppsLaunchFailureReceiver.java (limited to 'services/java') diff --git a/services/java/com/android/server/AppsFailureReceiver.java b/services/java/com/android/server/AppsFailureReceiver.java new file mode 100644 index 0000000..bebef9b --- /dev/null +++ b/services/java/com/android/server/AppsFailureReceiver.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2010, T-Mobile USA, Inc. + * Copyright (C) 2015 The CyanogenMod 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.server; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ThemeUtils; +import android.content.res.ThemeConfig; +import android.content.res.ThemeManager; +import android.os.SystemClock; +import android.provider.ThemesContract; + +import java.util.ArrayList; +import java.util.List; + +import com.android.internal.R; + +public class AppsFailureReceiver extends BroadcastReceiver { + + private static final int FAILURES_THRESHOLD = 3; + private static final int EXPIRATION_TIME_IN_MILLISECONDS = 30000; // 30 seconds + + private static final int THEME_RESET_NOTIFICATION_ID = 0x4641494C; + + private int mFailuresCount = 0; + private long mStartTime = 0; + + // This function implements the following logic. + // If after a theme was applied the number of application launch failures + // at any moment was equal to FAILURES_THRESHOLD + // in less than EXPIRATION_TIME_IN_MILLISECONDS + // the default theme is applied unconditionally. + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_APP_FAILURE)) { + long currentTime = SystemClock.uptimeMillis(); + String pkgName = intent.getStringExtra("package"); + if (currentTime - mStartTime > EXPIRATION_TIME_IN_MILLISECONDS) { + // reset both the count and the timer + mStartTime = currentTime; + mFailuresCount = 0; + } + if (mFailuresCount <= FAILURES_THRESHOLD) { + mFailuresCount++; + if (mFailuresCount == FAILURES_THRESHOLD) { + // let the theme manager take care of getting us back on the default theme + ThemeManager tm = + (ThemeManager) context.getSystemService(Context.THEME_SERVICE); + List components = new ArrayList(); + components.add(ThemesContract.ThemesColumns.MODIFIES_FONTS); + components.add(ThemesContract.ThemesColumns.MODIFIES_LAUNCHER); + components.add(ThemesContract.ThemesColumns.MODIFIES_ALARMS); + components.add(ThemesContract.ThemesColumns.MODIFIES_BOOT_ANIM); + components.add(ThemesContract.ThemesColumns.MODIFIES_ICONS); + components.add(ThemesContract.ThemesColumns.MODIFIES_LOCKSCREEN); + components.add(ThemesContract.ThemesColumns.MODIFIES_NOTIFICATIONS); + components.add(ThemesContract.ThemesColumns.MODIFIES_OVERLAYS); + components.add(ThemesContract.ThemesColumns.MODIFIES_RINGTONES); + components.add(ThemesContract.ThemesColumns.MODIFIES_STATUS_BAR); + components.add(ThemesContract.ThemesColumns.MODIFIES_NAVIGATION_BAR); + tm.requestThemeChange(ThemeConfig.SYSTEM_DEFAULT, components); + postThemeResetNotification(context); + } + } + } else if (action.equals(Intent.ACTION_APP_FAILURE_RESET) + || action.equals(ThemeUtils.ACTION_THEME_CHANGED)) { + mFailuresCount = 0; + mStartTime = SystemClock.uptimeMillis(); + } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) || + action.equals(Intent.ACTION_PACKAGE_REMOVED)) { + mFailuresCount = 0; + mStartTime = SystemClock.uptimeMillis(); + } + } + + /** + * Posts a notification to let the user know their theme was reset + * @param context + */ + private void postThemeResetNotification(Context context) { + NotificationManager nm = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + String title = context.getString(R.string.theme_reset_notification_title); + String body = context.getString(R.string.theme_reset_notification_body); + Notification notice = new Notification.Builder(context) + .setAutoCancel(true) + .setOngoing(false) + .setContentTitle(title) + .setContentText(body) + .setStyle(new Notification.BigTextStyle().bigText(body)) + .setSmallIcon(android.R.drawable.stat_notify_error) + .setWhen(System.currentTimeMillis()) + .setCategory(Notification.CATEGORY_SYSTEM) + .setPriority(Notification.PRIORITY_MAX) + .build(); + nm.notify(THEME_RESET_NOTIFICATION_ID, notice); + } +} diff --git a/services/java/com/android/server/AppsLaunchFailureReceiver.java b/services/java/com/android/server/AppsLaunchFailureReceiver.java deleted file mode 100644 index 81b23ec..0000000 --- a/services/java/com/android/server/AppsLaunchFailureReceiver.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2010, T-Mobile USA, Inc. - * - * 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.server; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ThemeUtils; -import android.content.res.ThemeConfig; -import android.content.res.ThemeManager; -import android.os.SystemClock; -import android.provider.ThemesContract; - -import java.util.ArrayList; -import java.util.List; - -public class AppsLaunchFailureReceiver extends BroadcastReceiver { - - private static final int FAILURES_THRESHOLD = 3; - private static final int EXPIRATION_TIME_IN_MILLISECONDS = 30000; // 30 seconds - - private int mFailuresCount = 0; - private long mStartTime = 0; - - // This function implements the following logic. - // If after a theme was applied the number of application launch failures - // at any moment was equal to FAILURES_THRESHOLD - // in less than EXPIRATION_TIME_IN_MILLISECONDS - // the default theme is applied unconditionally. - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(Intent.ACTION_APP_LAUNCH_FAILURE)) { - long currentTime = SystemClock.uptimeMillis(); - if (currentTime - mStartTime > EXPIRATION_TIME_IN_MILLISECONDS) { - // reset both the count and the timer - mStartTime = currentTime; - mFailuresCount = 0; - } - if (mFailuresCount <= FAILURES_THRESHOLD) { - mFailuresCount++; - if (mFailuresCount == FAILURES_THRESHOLD) { - // let the theme manager take care of getting us back on the default theme - ThemeManager tm = - (ThemeManager) context.getSystemService(Context.THEME_SERVICE); - List components = new ArrayList(); - components.add(ThemesContract.ThemesColumns.MODIFIES_FONTS); - components.add(ThemesContract.ThemesColumns.MODIFIES_LAUNCHER); - components.add(ThemesContract.ThemesColumns.MODIFIES_ALARMS); - components.add(ThemesContract.ThemesColumns.MODIFIES_BOOT_ANIM); - components.add(ThemesContract.ThemesColumns.MODIFIES_ICONS); - components.add(ThemesContract.ThemesColumns.MODIFIES_LOCKSCREEN); - components.add(ThemesContract.ThemesColumns.MODIFIES_NOTIFICATIONS); - components.add(ThemesContract.ThemesColumns.MODIFIES_OVERLAYS); - components.add(ThemesContract.ThemesColumns.MODIFIES_RINGTONES); - components.add(ThemesContract.ThemesColumns.MODIFIES_STATUS_BAR); - components.add(ThemesContract.ThemesColumns.MODIFIES_NAVIGATION_BAR); - tm.requestThemeChange(ThemeConfig.SYSTEM_DEFAULT, components); - } - } - } else if (action.equals(Intent.ACTION_APP_LAUNCH_FAILURE_RESET) - || action.equals(ThemeUtils.ACTION_THEME_CHANGED)) { - mFailuresCount = 0; - mStartTime = SystemClock.uptimeMillis(); - } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) || - action.equals(Intent.ACTION_PACKAGE_REMOVED)) { - mFailuresCount = 0; - mStartTime = SystemClock.uptimeMillis(); - } - } - -} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b4427ec..48deb68 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1152,14 +1152,14 @@ public final class SystemServer { } IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_APP_LAUNCH_FAILURE); - filter.addAction(Intent.ACTION_APP_LAUNCH_FAILURE_RESET); + filter.addAction(Intent.ACTION_APP_FAILURE); + filter.addAction(Intent.ACTION_APP_FAILURE_RESET); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(ThemeUtils.ACTION_THEME_CHANGED); filter.addCategory(Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE); filter.addDataScheme("package"); - context.registerReceiver(new AppsLaunchFailureReceiver(), filter); + context.registerReceiver(new AppsFailureReceiver(), filter); // These are needed to propagate to the runnable below. final NetworkManagementService networkManagementF = networkManagement; -- cgit v1.1