Skip to content

Commit

Permalink
Better handling of modem panics
Browse files Browse the repository at this point in the history
Unlike the stock ROM, we don't simply exec /sbin/reboot, but present UI
to the user where he can cancel the reboot (if he's currently doing
something) and is presented with a notice after the reboot.

Change-Id: Ib64ad901b9c407d21434e2cd7048b66f86bb443f
  • Loading branch information
maniac103 authored and nadlabak committed Dec 6, 2012
1 parent 28c54ce commit a0ad7d2
Show file tree
Hide file tree
Showing 10 changed files with 356 additions and 2 deletions.
18 changes: 18 additions & 0 deletions MmParts/AndroidManifest.xml
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
android:versionCode="1" android:versionCode="1"
android:versionName="1.0" > android:versionName="1.0" >


<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.REBOOT" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application <application
android:label="@string/app_name" > android:label="@string/app_name" >
<activity <activity
Expand All @@ -14,6 +18,20 @@
<action android:name="com.cyanogenmod.action.LAUNCH_DEVICE_SETTINGS" /> <action android:name="com.cyanogenmod.action.LAUNCH_DEVICE_SETTINGS" />
</intent-filter> </intent-filter>
</activity> </activity>

<activity android:name=".BpPanicNotifyActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />

<activity android:name=".BpPanicRebootNoticeActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />

<receiver android:name=".BpPanicReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

<service android:name=".BpPanicHandlerService" />
</application> </application>


</manifest> </manifest>
9 changes: 8 additions & 1 deletion MmParts/res/values-de/strings.xml
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -42,5 +42,12 @@
<string name="ui_status_bar_oneperc_battery_title">Batterie in 1% Schritten</string> <string name="ui_status_bar_oneperc_battery_title">Batterie in 1% Schritten</string>
<string name="ui_status_bar_oneperc_battery_summary">Zeigt den Ladezustand der Batterie in 1% Schritten. Kann Probleme mit Batterien und Ladegeräten von Fremdherstellern verursachen. (erfordert Neustart)</string> <string name="ui_status_bar_oneperc_battery_summary">Zeigt den Ladezustand der Batterie in 1% Schritten. Kann Probleme mit Batterien und Ladegeräten von Fremdherstellern verursachen. (erfordert Neustart)</string>



<string name="modem_error">Modem-Problem</string>
<string name="touch_for_info">Berühren für Informationen</string>
<string name="reboot_timeout_msg">Wenn keine Option gewählt wird, wird das Gerät in %1$d Sekunden neu gestartet.</string>
<string name="modem_error_msg">Im Modem des Telefons wurde ein Problem festgestellt. Um es zu beheben, muss das Gerät neu gestartet werden.\nWas möchten Sie tun?</string>
<string name="reboot_btn">Neu starten</string>
<string name="snooze_btn">Später erinnern</string>
<string name="dismiss_btn">Nicht mehr erinnern</string>
<string name="device_rebooted_modem_error">Das Gerät wurde auf Grund eines Problems im Modem des Telefons neu gestartet.</string>
</resources> </resources>
8 changes: 8 additions & 0 deletions MmParts/res/values/strings.xml
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -41,4 +41,12 @@
<string name="ui_status_bar_oneperc_battery_title">1% battery steps</string> <string name="ui_status_bar_oneperc_battery_title">1% battery steps</string>
<string name="ui_status_bar_oneperc_battery_summary">Show battery percentage in 1% steps. May cause issues with third party batteries and AC adapters. (Requires reboot)</string> <string name="ui_status_bar_oneperc_battery_summary">Show battery percentage in 1% steps. May cause issues with third party batteries and AC adapters. (Requires reboot)</string>


<string name="modem_error">Telephony problem</string>
<string name="touch_for_info">Touch for information</string>
<string name="reboot_timeout_msg">If no action is selected, the device will reboot in %1$d seconds.</string>
<string name="modem_error_msg">A problem was detected in the phone\'s telephony layer. A reboot of the phone is required to repair the phone state.\nWhat do you want to do?</string>
<string name="reboot_btn">Reboot now</string>
<string name="snooze_btn">Remind again later</string>
<string name="dismiss_btn">Don\'t remind again</string>
<string name="device_rebooted_modem_error">The device was rebooted due to a problem in the phone\'s telephony layer.</string>
</resources> </resources>
134 changes: 134 additions & 0 deletions MmParts/src/com/cyanogenmod/mmparts/BpPanicHandlerService.java
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,134 @@
package com.cyanogenmod.mmparts;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.content.Intent;
import android.os.IBinder;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;

public class BpPanicHandlerService extends Service {
private static final String TAG = "BpPanicHandlerService";
private static final int NOTIFICATION_ID = 1;

private static final String ACTION_HANDLE_PANIC = "com.cyanogenmod.mmparts.action.HANDLE_BP_PANIC";
static final String ACTION_TIMER_UPDATE = "com.cyanogenmod.mmparts.action.TIMER_UPDATE";
static final String ACTION_REBOOT = "com.cyanogenmod.mmparts.action.BP_PANIC_REBOOT";
static final String ACTION_SNOOZE = "com.cyanogenmod.mmparts.action.REMIND_LATER";
static final String ACTION_DISMISS = "com.cyanogenmod.mmparts.action.DISMISS";

static final String EXTRA_TIMEOUT = "timeout";

static final String KEY_NEED_REBOOT_NOTICE = "need_bppanic_reboot_notice";

private static final long SNOOZE_DELAY = 5 * 60 * 1000; /* 5 minutes */
private static final long REBOOT_TIMEOUT = 60 * 1000; /* 1 minute */

private SharedPreferences mPrefs;
private AlarmManager mAM;
private long mRebootTimeout = -1;
private Notification mNotification;
private Intent mNotifyIntent;
private PendingIntent mTimerUpdateIntent;
private PendingIntent mPanicHandleIntent;

@Override
public void onCreate() {
super.onCreate();

mAM = (AlarmManager) getSystemService(ALARM_SERVICE);
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);

Intent intent = new Intent(this, getClass());
intent.setAction(ACTION_HANDLE_PANIC);
mPanicHandleIntent = PendingIntent.getService(this, 0, intent, 0);

intent = new Intent(this, getClass());
intent.setAction(ACTION_TIMER_UPDATE);
mTimerUpdateIntent = PendingIntent.getService(this, 1, intent, 0);

mNotifyIntent = new Intent(this, BpPanicNotifyActivity.class);
mNotifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();

if (TextUtils.equals(action, ACTION_HANDLE_PANIC)) {
Log.d(TAG, "Got BP panic intent");
if (mNotification == null) {
mNotification = createNotification();
}
mRebootTimeout = System.currentTimeMillis() + REBOOT_TIMEOUT;
updateTimeout();
startActivity(mNotifyIntent);
startForeground(NOTIFICATION_ID, mNotification);
} else if (TextUtils.equals(action, ACTION_REBOOT)) {
doReboot(false);
} else if (TextUtils.equals(action, ACTION_SNOOZE)) {
cancelTimeout();
schedule(mPanicHandleIntent, SNOOZE_DELAY);
} else if (TextUtils.equals(action, ACTION_DISMISS)) {
cancelTimeout();
} else if (TextUtils.equals(action, ACTION_TIMER_UPDATE)) {
updateTimeout();
}

return START_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
return null;
}

private void schedule(PendingIntent intent, long timeout) {
mAM.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeout, intent);
}

private void cancelTimeout() {
removeStickyBroadcast(new Intent(ACTION_TIMER_UPDATE));
mRebootTimeout = -1;
mAM.cancel(mTimerUpdateIntent);
}

private Notification createNotification() {
Notification notification = new Notification(android.R.drawable.stat_notify_error, null, System.currentTimeMillis());
notification.defaults |= Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE;
notification.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_SHOW_LIGHTS;
notification.ledARGB = Color.RED;
notification.ledOnMS = 1000;
notification.ledOffMS = 0;
notification.setLatestEventInfo(this,
getString(R.string.modem_error),
getString(R.string.touch_for_info),
PendingIntent.getActivity(this, 0, mNotifyIntent, 0));

return notification;
}

private void updateTimeout() {
int timeout = (int) (mRebootTimeout - System.currentTimeMillis() + 500) / 1000;
if (timeout <= 0) {
doReboot(true);
} else {
Intent intent = new Intent(ACTION_TIMER_UPDATE);
intent.putExtra(EXTRA_TIMEOUT, timeout);
sendStickyBroadcast(intent);
schedule(mTimerUpdateIntent, timeout <= 5 ? 1000 : 5000);
}
}

private void doReboot(boolean requireNotice) {
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
mPrefs.edit().putBoolean(KEY_NEED_REBOOT_NOTICE, requireNotice).commit();
pm.reboot("bppanic");
}
}
100 changes: 100 additions & 0 deletions MmParts/src/com/cyanogenmod/mmparts/BpPanicNotifyActivity.java
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.cyanogenmod.mmparts;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;

public class BpPanicNotifyActivity extends Activity implements DialogInterface.OnClickListener {
private static final int DIALOG_ACTION_SELECT = 1;

private AlertDialog mDialog;

private BroadcastReceiver mTimerUpdateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int timeout = intent.getIntExtra(BpPanicHandlerService.EXTRA_TIMEOUT, -1);
updateDialogMessage(timeout);
}
};

@Override
protected Dialog onCreateDialog(int id, Bundle args) {
if (id == DIALOG_ACTION_SELECT) {
mDialog = new AlertDialog.Builder(this)
.setTitle(R.string.modem_error)
.setMessage(R.string.modem_error_msg)
.setCancelable(false)
.setPositiveButton(R.string.reboot_btn, this)
.setNeutralButton(R.string.snooze_btn, this)
.setNegativeButton(R.string.dismiss_btn, this)
.create();
return mDialog;
}

return super.onCreateDialog(id, args);
}

@Override
protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
if (id == DIALOG_ACTION_SELECT) {
updateDialogMessage(-1);
}
super.onPrepareDialog(id, dialog, args);
}

@Override
protected void onResume() {
super.onResume();
showDialog(DIALOG_ACTION_SELECT);
registerReceiver(mTimerUpdateReceiver, new IntentFilter(BpPanicHandlerService.ACTION_TIMER_UPDATE));
}

@Override
protected void onPause() {
unregisterReceiver(mTimerUpdateReceiver);
super.onPause();
}

private void doServiceAction(String action) {
Intent intent = new Intent(this, BpPanicHandlerService.class);
intent.setAction(action);
startService(intent);
}

public void onClick(DialogInterface dialog, int which) {
String action;

switch (which) {
case DialogInterface.BUTTON_POSITIVE:
action = BpPanicHandlerService.ACTION_REBOOT;
break;
case DialogInterface.BUTTON_NEUTRAL:
action = BpPanicHandlerService.ACTION_SNOOZE;
break;
case DialogInterface.BUTTON_NEGATIVE:
action = BpPanicHandlerService.ACTION_DISMISS;
break;
default:
return;
}

doServiceAction(action);
finish();
}

private void updateDialogMessage(int timeout) {
StringBuilder message = new StringBuilder();
message.append(getString(R.string.modem_error_msg));
if (timeout >= 0) {
message.append("\n\n");
message.append(getString(R.string.reboot_timeout_msg, timeout));
}
mDialog.setMessage(message.toString());
}
}
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.cyanogenmod.mmparts;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;

public class BpPanicRebootNoticeActivity extends Activity {
private static final int DIALOG_NOTICE = 1;

@Override
protected Dialog onCreateDialog(int id, Bundle args) {
if (id == DIALOG_NOTICE) {
return new AlertDialog.Builder(this)
.setTitle(R.string.modem_error)
.setMessage(R.string.device_rebooted_modem_error)
.setNegativeButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
finish();
}
})
.create();
}

return super.onCreateDialog(id, args);
}

@Override
protected void onResume() {
super.onResume();
showDialog(DIALOG_NOTICE);
}

@Override
protected void onPause() {
dismissDialog(DIALOG_NOTICE);
super.onPause();
}
}
26 changes: 26 additions & 0 deletions MmParts/src/com/cyanogenmod/mmparts/BpPanicReceiver.java
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.cyanogenmod.mmparts;

import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

public class BpPanicReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();

if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (prefs.getBoolean(BpPanicHandlerService.KEY_NEED_REBOOT_NOTICE, false)) {
Intent noticeIntent = new Intent(context, BpPanicRebootNoticeActivity.class);
noticeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

context.startActivity(noticeIntent);
prefs.edit().putBoolean(BpPanicHandlerService.KEY_NEED_REBOOT_NOTICE, false).commit();
}
}
}
}
11 changes: 11 additions & 0 deletions prebuilt/bin/handle_bp_panic.sh
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/system/bin/sh

# stop panic_daemon restarting
setprop ctl.stop panic_daemon

# let UI handle the failure
am startservice -a com.cyanogenmod.mmparts.action.HANDLE_BP_PANIC -n com.cyanogenmod.mmparts/.BpPanicHandlerService 2>&1 | grep Error
if [ $? -eq 0 ]; then
# some error occured, use fallback and reboot directly
reboot bppanic
fi
2 changes: 1 addition & 1 deletion rootfs/init.mapphone_umts.rc
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ service panic_daemon /system/bin/panic_daemon
user radio user radio
group radio system graphics group radio system graphics
socket panic_daemon stream 660 radio radio socket panic_daemon stream 660 radio radio
onrestart exec /system/bin/reboot onrestart exec /system/bin/sh /system/bin/handle_bp_panic.sh


# Ecompass daemon # Ecompass daemon
service akmd2 /system/bin/akmd2 service akmd2 /system/bin/akmd2
Expand Down
Loading

0 comments on commit a0ad7d2

Please sign in to comment.